@usebutr/bitcoin 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ type BitcoinSignMessageOutput = {
11
11
  signedMessage: Uint8Array;
12
12
  };
13
13
  type BitcoinSignMessageFeature = {
14
- signMessage(input: BitcoinSignMessageInput): Promise<BitcoinSignMessageOutput>;
14
+ signMessage: (input: BitcoinSignMessageInput) => Promise<BitcoinSignMessageOutput>;
15
15
  };
16
16
  type BitcoinSignPsbtInput = {
17
17
  account: WalletStandardWalletAccount; /** Network chain id (`bip122:…`). */
@@ -27,7 +27,7 @@ type BitcoinSignPsbtOutput = {
27
27
  signedPsbt: Uint8Array;
28
28
  };
29
29
  type BitcoinSignPsbtFeature = {
30
- signPsbt(input: BitcoinSignPsbtInput): Promise<BitcoinSignPsbtOutput>;
30
+ signPsbt: (input: BitcoinSignPsbtInput) => Promise<BitcoinSignPsbtOutput>;
31
31
  };
32
32
  type BitcoinSendTransferInput = {
33
33
  account: WalletStandardWalletAccount;
@@ -39,7 +39,7 @@ type BitcoinSendTransferOutput = {
39
39
  /** Broadcast txid. */txid: string;
40
40
  };
41
41
  type BitcoinSendTransferFeature = {
42
- sendTransfer(input: BitcoinSendTransferInput): Promise<BitcoinSendTransferOutput>;
42
+ sendTransfer: (input: BitcoinSendTransferInput) => Promise<BitcoinSendTransferOutput>;
43
43
  };
44
44
  //#endregion
45
45
  //#region src/wallet-standard-adapter.d.ts
@@ -162,22 +162,10 @@ type BitcoinCapabilityInput = {
162
162
  */
163
163
  declare const resolveBitcoinCapabilities: (input: BitcoinCapabilityInput) => WalletCapabilities;
164
164
  //#endregion
165
- //#region src/injected/icon.d.ts
166
- /**
167
- * Generic Bitcoin wallet icon — same purse SVG style as the EVM
168
- * package, recoloured. Inline so the picker doesn't flash.
169
- *
170
- * Lives in its own file because both injected adapters (UniSat-shape
171
- * and sats-connect) need the same fallback when the wallet doesn't
172
- * advertise its own icon, and there's no other "shared" thing they
173
- * both want — a one-line module beats a grab-bag.
174
- */
175
- declare const GENERIC_BITCOIN_ICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2Y3OTMxYSIgc3Ryb2tlPSJub25lIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjx0ZXh0IHg9IjEyIiB5PSIxNyIgZm9udC1mYW1pbHk9InNlcmlmIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QjwvdGV4dD48L3N2Zz4=";
176
- //#endregion
177
165
  //#region src/injected/sats-connect.d.ts
178
166
  /** sats-connect (Xverse) shape — a JSON-RPC-ish `request(method, params)`. */
179
167
  type SatsConnectProvider = {
180
- request(method: string, params?: Record<string, unknown>): Promise<{
168
+ request: (method: string, params?: Record<string, unknown>) => Promise<{
181
169
  error?: {
182
170
  message: string;
183
171
  };
@@ -199,15 +187,15 @@ type SatsConnectProvider = {
199
187
  * same four methods every UniSat-derivative wallet exposes (UniSat
200
188
  * itself, OKX Wallet's Bitcoin path at `window.okxwallet.bitcoin`). */
201
189
  type UnisatProvider = {
202
- getAccounts(): Promise<ReadonlyArray<string>>;
203
- getNetwork?(): Promise<"livenet" | "mainnet" | "testnet" | "signet">;
204
- on?(event: "accountsChanged" | "networkChanged", listener: (...args: Array<unknown>) => void): void;
205
- pushPsbt?(psbtHex: string): Promise<string>;
206
- removeListener?(event: "accountsChanged" | "networkChanged", listener: (...args: Array<unknown>) => void): void;
207
- requestAccounts(): Promise<ReadonlyArray<string>>;
208
- sendBitcoin?(recipient: string, amount: number): Promise<string>;
209
- signMessage(message: string, type?: "ecdsa" | "bip322-simple"): Promise<string>;
210
- signPsbt(psbtHex: string, options?: Record<string, unknown>): Promise<string>;
190
+ getAccounts: () => Promise<ReadonlyArray<string>>;
191
+ getNetwork?: () => Promise<"livenet" | "mainnet" | "testnet" | "signet">;
192
+ on?: (event: "accountsChanged" | "networkChanged", listener: (...args: Array<unknown>) => void) => void;
193
+ pushPsbt?: (psbtHex: string) => Promise<string>;
194
+ removeListener?: (event: "accountsChanged" | "networkChanged", listener: (...args: Array<unknown>) => void) => void;
195
+ requestAccounts: () => Promise<ReadonlyArray<string>>;
196
+ sendBitcoin?: (recipient: string, amount: number) => Promise<string>;
197
+ signMessage: (message: string, type?: "ecdsa" | "bip322-simple") => Promise<string>;
198
+ signPsbt: (psbtHex: string, options?: Record<string, unknown>) => Promise<string>;
211
199
  };
212
200
  /**
213
201
  * Wrap a UniSat-style provider (`window.unisat`, `window.okxwallet.bitcoin`,
@@ -218,6 +206,18 @@ type UnisatProvider = {
218
206
  * gated by feature detection per call.
219
207
  */
220
208
  //#endregion
209
+ //#region src/injected/icon.d.ts
210
+ /**
211
+ * Generic Bitcoin wallet icon — same purse SVG style as the EVM
212
+ * package, recoloured. Inline so the picker doesn't flash.
213
+ *
214
+ * Lives in its own file because both injected adapters (UniSat-shape
215
+ * and sats-connect) need the same fallback when the wallet doesn't
216
+ * advertise its own icon, and there's no other "shared" thing they
217
+ * both want — a one-line module beats a grab-bag.
218
+ */
219
+ declare const GENERIC_BITCOIN_ICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2Y3OTMxYSIgc3Ryb2tlPSJub25lIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjx0ZXh0IHg9IjEyIiB5PSIxNyIgZm9udC1mYW1pbHk9InNlcmlmIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QjwvdGV4dD48L3N2Zz4=";
220
+ //#endregion
221
221
  //#region src/injected/index.d.ts
222
222
  type InjectedHost = {
223
223
  btc?: UnisatProvider;
@@ -281,13 +281,13 @@ declare const bitcoinDiscoverer: PlatformDiscoverer;
281
281
  * to runtime-narrow.
282
282
  */
283
283
  type UnisatLike = {
284
- getAccounts(): Promise<ReadonlyArray<string>>;
285
- requestAccounts(): Promise<ReadonlyArray<string>>;
286
- signMessage(message: string, type?: string): Promise<string>;
287
- signPsbt(psbtHex: string, options?: Record<string, unknown>): Promise<string>;
284
+ getAccounts: () => Promise<ReadonlyArray<string>>;
285
+ requestAccounts: () => Promise<ReadonlyArray<string>>;
286
+ signMessage: (message: string, type?: string) => Promise<string>;
287
+ signPsbt: (psbtHex: string, options?: Record<string, unknown>) => Promise<string>;
288
288
  };
289
289
  type SatsConnectLike = {
290
- request(method: string, params?: Record<string, unknown>): Promise<{
290
+ request: (method: string, params?: Record<string, unknown>) => Promise<{
291
291
  error?: {
292
292
  message: string;
293
293
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/wallet-standard-types.ts","../src/wallet-standard-adapter.ts","../src/wallet-standard.ts","../src/chains.ts","../src/capabilities.ts","../src/injected/icon.ts","../src/injected/sats-connect.ts","../src/injected/unisat.ts","../src/injected/index.ts","../src/discoverer.ts","../src/signer-augmentation.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/wallet-standard-types.ts","../src/wallet-standard-adapter.ts","../src/wallet-standard.ts","../src/chains.ts","../src/capabilities.ts","../src/injected/sats-connect.ts","../src/injected/unisat.ts","../src/injected/icon.ts","../src/injected/index.ts","../src/discoverer.ts","../src/signer-augmentation.ts"],"mappings":";;;;KAgBK,uBAAA;EACH,OAAA,EAAS,2BAAA;EACT,OAAA,EAAS,UAAU;AAAA;AAAA,KAGhB,wBAAA;EACH,SAAA,EAAW,UAAA;EACX,aAAA,EAAe,UAAU;AAAA;AAAA,KAGtB,yBAAA;EACH,WAAA,GAAc,KAAA,EAAO,uBAAA,KAA4B,OAAA,CAAQ,wBAAA;AAAA;AAAA,KAGtD,oBAAA;EACH,OAAA,EAAS,2BAAA,EAJY;EAMrB,KAAA,UANiD;EAQjD,IAAA,EAAM,UAAA;EARkD;;EAWxD,UAAA,GAAa,aAAA;AAAA;AAAA,KAGV,qBAAA;EAdsD;;EAiBzD,UAAA,EAAY,UAAU;AAAA;AAAA,KAGnB,sBAAA;EACH,QAAA,GAAW,KAAA,EAAO,oBAAA,KAAyB,OAAA,CAAQ,qBAAA;AAAA;AAAA,KAGhD,wBAAA;EACH,OAAA,EAAS,2BAA2B;EACpC,MAAA;EACA,KAAA;EACA,SAAA;AAAA;AAAA,KAGG,yBAAA;EAvBH,sBAyBA,IAAI;AAAA;AAAA,KAGD,0BAAA;EACH,YAAA,GAAe,KAAA,EAAO,wBAAA,KAA6B,OAAA,CAAQ,yBAAA;AAAA;;;cCrCvD,OAAA,GAAW,IAAY;;ADbsD;;;;;;;;;AAI9D;AAAA;;;;;;;;;AAKM;AAAA;;;;;cCmDrB,mBAAA,GACJ,MAAA,EAAQ,oBAAA;;;;;AAIR,oBAAA,IAAwB,IAAA,0BACvB,aAAa;;;;;;ADlEmE;;;;;;;;;AAI9D;AAAA;cECf,uBAAA,GAA2B,SAAA,GAAY,OAAA,EAAS,aAAa;;;;;;AFLgB;;;;;;;;;AAI9D;AAAA;;;;cGCf,cAAA;EAAA;;;;;;;;;;;;;;;;;;;cAqBA,mBAAA,EAAqB,aAAa,CAAC,SAAA;;;KCtCpC,sBAAA;EACH,UAAA;EACA,QAAA;IACE,MAAA;IACA,YAAA;IACA,WAAA;IACA,QAAA;EAAA;AAAA;;;;AJUiB;AAAA;;;;;;;;;AAKM;AAAA;;cIKrB,0BAAA,GAA8B,KAAA,EAAO,sBAAA,KAAyB,kBAWlE;;;;KC9BG,mBAAA;EACH,OAAA,GACE,MAAA,UACA,MAAA,GAAS,MAAA,sBACN,OAAO;IAAG,KAAA;MAAU,OAAA;IAAA;IAAmB,MAAA;EAAA;AAAA;;;;ALKzB;AAAA;;;;;;;;;;KMPhB,cAAA;EACH,WAAA,QAAmB,OAAA,CAAQ,aAAA;EAC3B,UAAA,SAAmB,OAAA;EACnB,EAAA,IACE,KAAA,wCACA,QAAA,MAAc,IAAA,EAAM,KAAA;EAEtB,QAAA,IAAY,OAAA,aAAoB,OAAA;EAChC,cAAA,IACE,KAAA,wCACA,QAAA,MAAc,IAAA,EAAM,KAAA;EAEtB,eAAA,QAAuB,OAAA,CAAQ,aAAA;EAC/B,WAAA,IAAe,SAAA,UAAmB,MAAA,aAAmB,OAAA;EACrD,WAAA,GAAc,OAAA,UAAiB,IAAA,iCAAqC,OAAA;EACpE,QAAA,GAAW,OAAA,UAAiB,OAAA,GAAU,MAAA,sBAA4B,OAAA;AAAA;;;;;;;;;;;;;;;ANZe;;;;;cOL7E,oBAAA;;;KCAD,YAAA;EACH,GAAA,GAAM,cAAA;EACN,SAAA;IAAc,OAAA,GAAU,cAAA;EAAA;EACxB,MAAA,GAAS,cAAA;EACT,eAAA;IAAoB,eAAA,GAAkB,mBAAA;EAAA;AAAA;AAAA,KAGnC,+BAAA;ERKA;;EQFH,2BAAA;ERIyB;;EQDzB,QAAA,WRCA;EQCA,MAAA,GAAS,YAAY;AAAA;ARDI;AAAA;;;;;;;;;;;;;;AAAA,cQuDrB,8BAAA,GACJ,SAAA,GAAY,OAAA,EAAS,aAAA,WACrB,OAAA,GAAS,+BAAoC;;;;;;ARlEoC;;;cSH7E,iBAAA,EAAmB,kBASxB;;;;;;ATNkF;;;;;;;;;AAI9D;AAAA;;KUDhB,UAAA;EACH,WAAA,QAAmB,OAAA,CAAQ,aAAA;EAC3B,eAAA,QAAuB,OAAA,CAAQ,aAAA;EAC/B,WAAA,GAAc,OAAA,UAAiB,IAAA,cAAkB,OAAA;EACjD,QAAA,GAAW,OAAA,UAAiB,OAAA,GAAU,MAAA,sBAA4B,OAAA;AAAA;AAAA,KAG/D,eAAA;EACH,OAAA,GACE,MAAA,UACA,MAAA,GAAS,MAAA,sBACN,OAAO;IAAG,KAAA;MAAU,OAAA;IAAA;IAAmB,MAAA;EAAA;AAAA;AAAA;EAAA,UAKlC,iBAAA;IACR,OAAA,EAAS,eAAA,GAAkB,UAAA,GAAa,oBAAA;EAAA;AAAA"}
package/dist/index.js CHANGED
@@ -1,2 +1,645 @@
1
- import{logWarn as e,sanitizeIcon as t}from"@usebutr/core";import{buildAccount as n,discoverWalletStandard as r,getFeature as i,pickAccountByAddress as a,pickFirstAddress as o,slugify as s}from"@usebutr/wallet-standard-shared";const c=e=>({getBalance:!1,getTransactionReceipt:!1,requestAccounts:!1,sendTransaction:e.features.sendTransfer,signIn:!1,signMessage:e.features.signMessage,signTransaction:e.features.signPsbt,subscribe:e.features.events,switchAccount:!1,switchChain:e.chainCount>1}),l=`bip122:`,u=`bip122:000000000019d6689c085ae165831e93`,d=e=>s(`btc`,e),f=e=>e.chains.find(e=>e===u)||(e.chains.find(e=>e.startsWith(l))??null),p=(e,t)=>({id:e,name:t,namespace:`bip122`,reference:e.slice(7)}),m=(e,t)=>n(e,t),h=(n,r)=>{let s=f(n);if(!s)return null;let h=i(n,`standard:connect`);if(!h)return null;let g=i(n,`standard:disconnect`),_=i(n,`standard:events`),v=i(n,`bitcoin:signMessage`),y=i(n,`bitcoin:signPsbt`),b=i(n,`bitcoin:sendTransfer`),x=s,S=()=>p(x,n.name),C=new Set,w=()=>{if(n.accounts.length===0)return;let e=S(),t=n.accounts.map(t=>m(t.address,e)),r=t[0];if(r)for(let e of C)e({account:r,accounts:t,type:`accountChanged`})};return r?.(()=>{for(let e of C)e({type:`disconnected`})}),{capabilities:c({chainCount:n.chains.filter(e=>e.startsWith(l)).length,features:{events:!!_,sendTransfer:!!b,signMessage:!!v,signPsbt:!!y}}),chainPlatform:`bitcoin`,async connect(e){await h.connect(e?.silent?{silent:!0}:void 0)},async disconnect(){if(g)try{await g.disconnect()}catch(t){e(`[butr] Bitcoin Wallet Standard disconnect threw:`,t)}},getAccount(){let e=o(n.accounts);return e?Promise.resolve(m(e,S())):Promise.resolve(null)},getAccounts(){let e=S();return Promise.resolve(n.accounts.map(t=>m(t.address,e)))},getBalance(){return Promise.resolve({decimals:8,formatted:`0`,symbol:`BTC`,value:0n})},getSigner(){return Promise.resolve(n)},getTransactionReceipt(){return Promise.resolve({status:`Pending`})},icon:t(n.icon),id:d(n.name),name:n.name,async requestAccounts(){await h.connect()},async sendTx(e,t){if(!b)throw Error(`Wallet ${n.name} does not advertise bitcoin:sendTransfer`);if(!e||typeof e!=`object`||typeof e.amount!=`bigint`||typeof e.recipient!=`string`)throw TypeError(`Bitcoin sendTx expects { amount: bigint, recipient: string } — pass the recipient address and an amount in satoshis`);let{amount:r,recipient:i}=e,o=t?a(n.accounts,t.walletAddress):n.accounts[0]??null;if(!o)throw Error(`No connected account`);return(await b.sendTransfer({account:o,amount:r,chain:x,recipient:i})).txid},sendTxToChain(e,t,n,r){return r?.(),this.sendTx(e,n)},async signMessage(e,t){if(!v)throw Error(`Wallet ${n.name} does not advertise bitcoin:signMessage`);let r=t?a(n.accounts,t.walletAddress):n.accounts[0]??null;if(!r)throw Error(`No connected account`);let i=await v.signMessage({account:r,message:e});return{signature:i.signature,signedMessage:i.signedMessage}},...y?{async signTransaction(e,t){let r=t?a(n.accounts,t.walletAddress):n.accounts[0]??null;if(!r)throw Error(`No connected account`);if(!(e instanceof Uint8Array))throw TypeError(`Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())`);return(await y.signPsbt({account:r,chain:x,psbt:e})).signedPsbt}}:{},subscribe(e){C.add(e);let t=null;if(_){let n=_.on(`change`,t=>{if(t.chains){let e=t.chains.find(e=>e===u)??t.chains.find(e=>e.startsWith(l));e&&(x=e)}if(t.accounts){if(t.accounts.length===0){e({type:`disconnected`});return}let n=S(),r=t.accounts.map(e=>m(e.address,n)),i=r[0];if(!i)return;e({account:i,accounts:r,type:`accountChanged`});return}t.chains&&w()});t=()=>n()}return()=>{C.delete(e),t?.()}},switchChain(e){if(e.namespace!==`bip122`)throw Error(`Bitcoin adapter received non-Bitcoin chain "${e.id}". Pass a chain with namespace "bip122".`);if(!n.chains.includes(e.id))throw Error(`Wallet ${n.name} does not advertise chain "${e.id}". Available: ${n.chains.join(`, `)}`);return x=e.id,w(),Promise.resolve()}}},g=e=>r(e,(e,t)=>h(e,t)),_={mainnet:{id:`bip122:000000000019d6689c085ae165831e93`,name:`Bitcoin`,namespace:`bip122`,reference:`000000000019d6689c085ae165831e93`},signet:{id:`bip122:00000008819873e925422c1ff0f99f7c`,name:`Bitcoin Signet`,namespace:`bip122`,reference:`00000008819873e925422c1ff0f99f7c`},testnet:{id:`bip122:000000000933ea01ad0ee984209779ba`,name:`Bitcoin Testnet`,namespace:`bip122`,reference:`000000000933ea01ad0ee984209779ba`}},v=Object.values(_),y=`data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2Y3OTMxYSIgc3Ryb2tlPSJub25lIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjx0ZXh0IHg9IjEyIiB5PSIxNyIgZm9udC1mYW1pbHk9InNlcmlmIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QjwvdGV4dD48L3N2Zz4=`,b={getBalance:!1,getTransactionReceipt:!1,requestAccounts:!0,sendTransaction:!0,signIn:!1,signMessage:!0,signTransaction:!0,subscribe:!1,switchAccount:!1,switchChain:!1},x=e=>{let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e+=1)n[e]=t.codePointAt(e)??0;return n},S=e=>{let t=``;for(let n of e)t+=String.fromCodePoint(n);return btoa(t)},C=(e,t,r)=>{let i=_.mainnet,a=[],o=async(e,t)=>{let n=await r.request(e,t);if(n.error)throw Error(`[butr/bitcoin] sats-connect ${e} failed: ${n.error.message}`);return n.result},s=async()=>{let e=await o(`getAccounts`,{message:`Connect to butr`,purposes:[`payment`,`ordinals`]});if(!e?.addresses)return[];let t=e.addresses.map(e=>e.address);return a=t,t};return{capabilities:b,chainPlatform:`bitcoin`,async connect(){await s()},disconnect(){return a=[],Promise.resolve()},async getAccount(){let e=a[0];if(e)return n(e,i);let t=(await s())[0];return t?n(t,i):null},async getAccounts(){return(a.length>0?a:await s()).map(e=>n(e,i))},getBalance(){return Promise.resolve({decimals:8,formatted:`0`,symbol:`BTC`,value:0n})},getSigner(){return Promise.resolve(r)},getTransactionReceipt(){return Promise.resolve({status:`Pending`})},icon:y,id:e,name:t,async requestAccounts(){await s()},async sendTx(e){if(!e||typeof e!=`object`||typeof e.recipient!=`string`||typeof e.amount!=`bigint`)throw TypeError(`Bitcoin sendTx expects { amount: bigint, recipient: string } — amount in satoshis`);let{amount:t,recipient:n}=e;return(await o(`sendTransfer`,{recipients:[{address:n,amount:t.toString()}]})).txid},sendTxToChain(e,t,n,r){return r?.(),this.sendTx(e)},async signMessage(e){let t=a[0];if(!t)throw Error(`No connected account`);return{signature:x((await o(`signMessage`,{address:t,message:new TextDecoder().decode(e)})).signature),signedMessage:e}},async signTransaction(e){if(!(e instanceof Uint8Array))throw TypeError(`Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())`);return x((await o(`signPsbt`,{psbt:S(e)})).psbt)},switchChain(e){if(e.namespace!==`bip122`)throw Error(`Bitcoin adapter received non-Bitcoin chain "${e.id}". Pass a chain with namespace "bip122".`);return i=e,Promise.resolve()}}},w={getBalance:!1,getTransactionReceipt:!1,requestAccounts:!0,sendTransaction:!0,signIn:!1,signMessage:!0,signTransaction:!0,subscribe:!0,switchAccount:!1,switchChain:!1},T=e=>{let t=``;for(let n of e)t+=n.toString(16).padStart(2,`0`);return t},E=e=>{let t=e.startsWith(`0x`)?e.slice(2):e,n=new Uint8Array(t.length/2);for(let e=0;e<n.length;e+=1)n[e]=Number.parseInt(t.slice(e*2,e*2+2),16);return n},D=e=>{let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e+=1)n[e]=t.codePointAt(e)??0;return n},O=(e,t,r)=>{let i=_.mainnet,a=new Set,o=async()=>{if(typeof r.getNetwork==`function`)try{let e=await r.getNetwork();i=e===`testnet`?_.testnet:e===`signet`?_.signet:_.mainnet}catch{}};return{capabilities:w,chainPlatform:`bitcoin`,async connect(e){if(e?.silent){if((await r.getAccounts()).length===0)throw Error(`No authorized accounts for silent reconnect`);await o();return}await r.requestAccounts(),await o()},disconnect(){return Promise.resolve()},async getAccount(){let e=(await r.getAccounts())[0];return e?(await o(),n(e,i)):null},async getAccounts(){let e=await r.getAccounts();return e.length===0?[]:(await o(),e.map(e=>n(e,i)))},getBalance(){return Promise.resolve({decimals:8,formatted:`0`,symbol:`BTC`,value:0n})},getSigner(){return Promise.resolve(r)},getTransactionReceipt(){return Promise.resolve({status:`Pending`})},icon:y,id:e,name:t,async requestAccounts(){await r.requestAccounts(),await o()},sendTx(e){if(typeof r.sendBitcoin!=`function`)throw TypeError(`Wallet ${t} does not expose sendBitcoin`);if(!e||typeof e!=`object`||typeof e.recipient!=`string`||typeof e.amount!=`bigint`)throw TypeError(`Bitcoin sendTx expects { amount: bigint, recipient: string } — amount in satoshis`);let{amount:n,recipient:i}=e,a=Number(n);return r.sendBitcoin(i,a)},sendTxToChain(e,t,n,r){return r?.(),this.sendTx(e)},async signMessage(e){let t=new TextDecoder().decode(e);return{signature:D(await r.signMessage(t)),signedMessage:e}},async signTransaction(e){if(!(e instanceof Uint8Array))throw TypeError(`Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())`);return E(await r.signPsbt(T(e)))},subscribe(e){a.add(e);let t=(...t)=>{let r=t[0]??[];if(r.length===0){e({type:`disconnected`});return}let a=r.map(e=>n(e,i)),o=a[0];o&&e({account:o,accounts:a,type:`accountChanged`})},s=()=>{o()};return r.on?.(`accountsChanged`,t),r.on?.(`networkChanged`,s),()=>{r.removeListener?.(`accountsChanged`,t),r.removeListener?.(`networkChanged`,s),a.delete(e)}},switchChain(e){if(e.namespace!==`bip122`)throw Error(`Bitcoin adapter received non-Bitcoin chain "${e.id}". Pass a chain with namespace "bip122".`);return i=e,o(),Promise.resolve()}}},k=e=>e===void 0?typeof window>`u`?null:window:e,A=e=>{let t=[],n=new Set;e.unisat&&!n.has(e.unisat)&&(n.add(e.unisat),t.push(O(`injected:bitcoin:unisat`,`Unisat`,e.unisat)));let r=e.okxwallet?.bitcoin;r&&!n.has(r)&&(n.add(r),t.push(O(`injected:bitcoin:okx`,`OKX Wallet (Bitcoin)`,r)));let i=e.XverseProviders?.BitcoinProvider;return i&&!n.has(i)&&(n.add(i),t.push(C(`injected:bitcoin:xverse`,`Xverse`,i))),e.btc&&!n.has(e.btc)&&(n.add(e.btc),t.push(O(`injected:bitcoin:legacy`,`Browser Bitcoin wallet`,e.btc))),t},j=(e,t={})=>{let n=t.settleMs??150,r=!1,i=setTimeout(()=>{if(r||t.hasAnyWalletStandardAdapter?.())return;let n=k(t.target);if(!n)return;let i=A(n);for(let t of i)e(t)},n);return()=>{r=!0,clearTimeout(i)}},M={fallback:{subscribe:(e,t)=>j(e,{hasAnyWalletStandardAdapter:t.hasAnyPrimaryAdapter})},platform:`bitcoin`,subscribe:g};export{_ as BITCOIN_CHAINS,v as BITCOIN_CHAINS_LIST,y as GENERIC_BITCOIN_ICON,M as bitcoinDiscoverer,h as buildBitcoinAdapter,g as discoverBitcoinAdapters,j as discoverInjectedBitcoinAdapter,c as resolveBitcoinCapabilities,d as slugify};
1
+ import { base64ToBytes, bytesToBase64, bytesToHex, hexToBytes, logWarn, sanitizeIcon } from "@usebutr/core";
2
+ import { buildAccount, discoverWalletStandard, getFeature, pickAccountByAddress, pickFirstAddress, slugify as slugify$1 } from "@usebutr/wallet-standard-shared";
3
+
4
+ //#region src/capabilities.ts
5
+ /**
6
+ * Bitcoin capability mapping.
7
+ *
8
+ * - `sendTransaction = bitcoin:sendTransfer present`. The wallet handles
9
+ * UTXO selection, fee estimation, signing, and broadcast.
10
+ * - `signTransaction = bitcoin:signPsbt present`. Sign-only PSBT path
11
+ * for consumers that build their own UTXO-shaped transactions with
12
+ * `bitcoinjs-lib` and broadcast through their own provider.
13
+ * - `signMessage = bitcoin:signMessage present`.
14
+ * - `signIn = false`. No Sign-In-With-Bitcoin standard yet (BIP-322 is
15
+ * message-signing oriented, not auth).
16
+ * - `subscribe = events present`. Most Bitcoin wallets don't emit
17
+ * change events portably; capabilities admits the truth.
18
+ * - `switchChain = false`. No portable per-call switch RPC across
19
+ * Bitcoin wallets — Xverse/Unisat/Phantom each pick their own network.
20
+ */
21
+ const resolveBitcoinCapabilities = (input) => ({
22
+ getBalance: false,
23
+ getTransactionReceipt: false,
24
+ requestAccounts: false,
25
+ sendTransaction: input.features.sendTransfer,
26
+ signIn: false,
27
+ signMessage: input.features.signMessage,
28
+ signTransaction: input.features.signPsbt,
29
+ subscribe: input.features.events,
30
+ switchAccount: false,
31
+ switchChain: input.chainCount > 1
32
+ });
33
+
34
+ //#endregion
35
+ //#region src/wallet-standard-adapter.ts
36
+ const BITCOIN_PREFIX = "bip122:";
37
+ const BITCOIN_DECIMALS = 8;
38
+ const BITCOIN_MAINNET_ID = "bip122:000000000019d6689c085ae165831e93";
39
+ const slugify = (name) => slugify$1("btc", name);
40
+ const pickBitcoinChain = (wallet) => {
41
+ const mainnet = wallet.chains.find((c) => c === BITCOIN_MAINNET_ID);
42
+ if (mainnet) return mainnet;
43
+ return wallet.chains.find((c) => c.startsWith(BITCOIN_PREFIX)) ?? null;
44
+ };
45
+ const buildBitcoinChain = (chainId, walletName) => ({
46
+ id: chainId,
47
+ name: walletName,
48
+ namespace: "bip122",
49
+ reference: chainId.slice(7)
50
+ });
51
+ const buildBitcoinAccount = (address, chain) => buildAccount(address, chain);
52
+ /**
53
+ * Adapt a Bitcoin Wallet Standard `Wallet` into a butr `WalletAdapter`.
54
+ *
55
+ * Returns `null` if the wallet doesn't advertise any `bip122:` chain or
56
+ * doesn't expose `standard:connect`. Same posture as the SVM/Sui
57
+ * adapters: gate features on what each wallet advertises, return
58
+ * placeholders for RPC reads, forward `subscribe` through
59
+ * `standard:events`.
60
+ *
61
+ * **Known limitations**
62
+ *
63
+ * - `getBalance` returns `{ value: 0n, symbol: "BTC" }`. Bitcoin
64
+ * balance lookups require an Esplora/Electrum/RPC client outside
65
+ * butr's scope.
66
+ * - `getTransactionReceipt` returns `"Pending"` for the same reason.
67
+ * - `sendTx` expects the consumer to pass `{ amount: bigint, recipient: string }`
68
+ * via butr's `unknown` tx parameter — the simplest mental model that
69
+ * maps onto `bitcoin:sendTransfer`. PSBT-shaped flows go through
70
+ * `signTransaction`.
71
+ * - `signTransaction` expects a `Uint8Array` PSBT (raw bytes) — the
72
+ * same shape `bitcoin:signPsbt` accepts. Consumers building with
73
+ * `bitcoinjs-lib` get bytes via `psbt.toBuffer()`.
74
+ * - `switchChain` is local-state-only; the capability flag is `false`
75
+ * when only one chain is advertised. Wallets that ship a real switch
76
+ * primitive (none today, portably) would need their own adapter.
77
+ */
78
+ const buildBitcoinAdapter = (wallet, registerDisconnector) => {
79
+ const bitcoinChainId = pickBitcoinChain(wallet);
80
+ if (!bitcoinChainId) return null;
81
+ const connect = getFeature(wallet, "standard:connect");
82
+ if (!connect) return null;
83
+ const disconnect = getFeature(wallet, "standard:disconnect");
84
+ const events = getFeature(wallet, "standard:events");
85
+ const signMessage = getFeature(wallet, "bitcoin:signMessage");
86
+ const signPsbt = getFeature(wallet, "bitcoin:signPsbt");
87
+ const sendTransfer = getFeature(wallet, "bitcoin:sendTransfer");
88
+ let currentChainId = bitcoinChainId;
89
+ const currentChain = () => buildBitcoinChain(currentChainId, wallet.name);
90
+ const listeners = /* @__PURE__ */ new Set();
91
+ const notifyAccountChanged = () => {
92
+ if (wallet.accounts.length === 0) return;
93
+ const chain = currentChain();
94
+ const built = wallet.accounts.map((a) => buildBitcoinAccount(a.address, chain));
95
+ const first = built[0];
96
+ if (!first) return;
97
+ for (const listener of listeners) listener({
98
+ account: first,
99
+ accounts: built,
100
+ type: "accountChanged"
101
+ });
102
+ };
103
+ registerDisconnector?.(() => {
104
+ for (const listener of listeners) listener({ type: "disconnected" });
105
+ });
106
+ return {
107
+ capabilities: resolveBitcoinCapabilities({
108
+ chainCount: wallet.chains.filter((c) => c.startsWith(BITCOIN_PREFIX)).length,
109
+ features: {
110
+ events: Boolean(events),
111
+ sendTransfer: Boolean(sendTransfer),
112
+ signMessage: Boolean(signMessage),
113
+ signPsbt: Boolean(signPsbt)
114
+ }
115
+ }),
116
+ chainPlatform: "bitcoin",
117
+ async connect(opts) {
118
+ await connect.connect(opts?.silent ? { silent: true } : void 0);
119
+ },
120
+ async disconnect() {
121
+ if (disconnect) try {
122
+ await disconnect.disconnect();
123
+ } catch (error) {
124
+ logWarn("[butr] Bitcoin Wallet Standard disconnect threw:", error);
125
+ }
126
+ },
127
+ getAccount() {
128
+ const address = pickFirstAddress(wallet.accounts);
129
+ if (!address) return Promise.resolve(null);
130
+ return Promise.resolve(buildBitcoinAccount(address, currentChain()));
131
+ },
132
+ getAccounts() {
133
+ const chain = currentChain();
134
+ return Promise.resolve(wallet.accounts.map((a) => buildBitcoinAccount(a.address, chain)));
135
+ },
136
+ getBalance() {
137
+ return Promise.resolve({
138
+ decimals: BITCOIN_DECIMALS,
139
+ formatted: "0",
140
+ symbol: "BTC",
141
+ value: 0n
142
+ });
143
+ },
144
+ getSigner() {
145
+ return Promise.resolve(wallet);
146
+ },
147
+ getTransactionReceipt() {
148
+ return Promise.resolve({ status: "Pending" });
149
+ },
150
+ icon: sanitizeIcon(wallet.icon),
151
+ id: slugify(wallet.name),
152
+ name: wallet.name,
153
+ async requestAccounts() {
154
+ await connect.connect();
155
+ },
156
+ async sendTx(tx, account) {
157
+ if (!sendTransfer) throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:sendTransfer`);
158
+ if (!tx || typeof tx !== "object" || typeof tx.amount !== "bigint" || typeof tx.recipient !== "string") throw new TypeError("Bitcoin sendTx expects { amount: bigint, recipient: string } — pass the recipient address and an amount in satoshis");
159
+ const { amount, recipient } = tx;
160
+ const wsAccount = account ? pickAccountByAddress(wallet.accounts, account.walletAddress) : wallet.accounts[0] ?? null;
161
+ if (!wsAccount) throw new Error("No connected account");
162
+ return (await sendTransfer.sendTransfer({
163
+ account: wsAccount,
164
+ amount,
165
+ chain: currentChainId,
166
+ recipient
167
+ })).txid;
168
+ },
169
+ sendTxToChain(tx, _targetChainId, account, cb) {
170
+ cb?.();
171
+ return this.sendTx(tx, account);
172
+ },
173
+ async signMessage(msg, account) {
174
+ if (!signMessage) throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:signMessage`);
175
+ const wsAccount = account ? pickAccountByAddress(wallet.accounts, account.walletAddress) : wallet.accounts[0] ?? null;
176
+ if (!wsAccount) throw new Error("No connected account");
177
+ const output = await signMessage.signMessage({
178
+ account: wsAccount,
179
+ message: msg
180
+ });
181
+ return {
182
+ signature: output.signature,
183
+ signedMessage: output.signedMessage
184
+ };
185
+ },
186
+ ...signPsbt ? { async signTransaction(tx, account) {
187
+ const wsAccount = account ? pickAccountByAddress(wallet.accounts, account.walletAddress) : wallet.accounts[0] ?? null;
188
+ if (!wsAccount) throw new Error("No connected account");
189
+ if (!(tx instanceof Uint8Array)) throw new TypeError("Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())");
190
+ return (await signPsbt.signPsbt({
191
+ account: wsAccount,
192
+ chain: currentChainId,
193
+ psbt: tx
194
+ })).signedPsbt;
195
+ } } : {},
196
+ subscribe(listener) {
197
+ listeners.add(listener);
198
+ let unsubWallet = null;
199
+ if (events) {
200
+ const unsub = events.on("change", (changes) => {
201
+ if (changes.chains) {
202
+ const next = changes.chains.find((c) => c === BITCOIN_MAINNET_ID) ?? changes.chains.find((c) => c.startsWith(BITCOIN_PREFIX));
203
+ if (next) currentChainId = next;
204
+ }
205
+ if (changes.accounts) {
206
+ if (changes.accounts.length === 0) {
207
+ listener({ type: "disconnected" });
208
+ return;
209
+ }
210
+ const chain = currentChain();
211
+ const built = changes.accounts.map((a) => buildBitcoinAccount(a.address, chain));
212
+ const first = built[0];
213
+ if (!first) return;
214
+ listener({
215
+ account: first,
216
+ accounts: built,
217
+ type: "accountChanged"
218
+ });
219
+ return;
220
+ }
221
+ if (changes.chains) notifyAccountChanged();
222
+ });
223
+ unsubWallet = () => unsub();
224
+ }
225
+ return () => {
226
+ listeners.delete(listener);
227
+ unsubWallet?.();
228
+ };
229
+ },
230
+ switchChain(chain) {
231
+ if (chain.namespace !== "bip122") throw new Error(`Bitcoin adapter received non-Bitcoin chain "${chain.id}". Pass a chain with namespace "bip122".`);
232
+ if (!wallet.chains.includes(chain.id)) throw new Error(`Wallet ${wallet.name} does not advertise chain "${chain.id}". Available: ${wallet.chains.join(", ")}`);
233
+ currentChainId = chain.id;
234
+ notifyAccountChanged();
235
+ return Promise.resolve();
236
+ }
237
+ };
238
+ };
239
+
240
+ //#endregion
241
+ //#region src/wallet-standard.ts
242
+ /**
243
+ * Subscribe to Bitcoin Wallet Standard announcements.
244
+ *
245
+ * Phantom (Bitcoin), Magic Eden, OKX Wallet (Bitcoin), and Leather
246
+ * advertise `bitcoin:*` features over the same `getWallets()` bus that
247
+ * SVM and Sui consume. `buildBitcoinAdapter` returns `null` for wallets
248
+ * that don't advertise any `bip122:` chain, so multi-chain wallets
249
+ * (Phantom: EVM + SVM + Sui + Bitcoin) produce one adapter per platform.
250
+ *
251
+ * Requires the **optional peer dependency** `@wallet-standard/app`.
252
+ *
253
+ * The discovery loop (dynamic import, dedupe, register / unregister
254
+ * bridge) lives in `@usebutr/wallet-standard-shared`.
255
+ */
256
+ const discoverBitcoinAdapters = (onAdapter) => discoverWalletStandard(onAdapter, (wallet, registerDisconnector) => buildBitcoinAdapter(wallet, registerDisconnector));
257
+
258
+ //#endregion
259
+ //#region src/chains.ts
260
+ /**
261
+ * CAIP-2 Bitcoin chain references use the first 8 bytes (big-endian)
262
+ * of each network's genesis block hash. These string ids are what
263
+ * Bitcoin Wallet Standard wallets (Phantom, Magic Eden, OKX) advertise
264
+ * in `wallet.chains`; the adapter's `switchChain` rejects anything else.
265
+ *
266
+ * - Mainnet: `bip122:000000000019d6689c085ae165831e93`
267
+ * - Testnet: `bip122:000000000933ea01ad0ee984209779ba`
268
+ * - Signet: `bip122:00000008819873e925422c1ff0f99f7c`
269
+ *
270
+ * Bitcoin has no per-call "switch chain" RPC across the major wallets,
271
+ * so butr's adapter treats chain as a wallet-side configuration —
272
+ * `switchChain` updates local state to influence subsequent calls (same
273
+ * posture as SVM). Bitcoin's `switchChain` capability is `false` by
274
+ * default; consumers building on top can opt in if their wallet exposes
275
+ * a switch primitive.
276
+ */
277
+ const BITCOIN_CHAINS = {
278
+ mainnet: {
279
+ id: "bip122:000000000019d6689c085ae165831e93",
280
+ name: "Bitcoin",
281
+ namespace: "bip122",
282
+ reference: "000000000019d6689c085ae165831e93"
283
+ },
284
+ signet: {
285
+ id: "bip122:00000008819873e925422c1ff0f99f7c",
286
+ name: "Bitcoin Signet",
287
+ namespace: "bip122",
288
+ reference: "00000008819873e925422c1ff0f99f7c"
289
+ },
290
+ testnet: {
291
+ id: "bip122:000000000933ea01ad0ee984209779ba",
292
+ name: "Bitcoin Testnet",
293
+ namespace: "bip122",
294
+ reference: "000000000933ea01ad0ee984209779ba"
295
+ }
296
+ };
297
+ const BITCOIN_CHAINS_LIST = Object.values(BITCOIN_CHAINS);
298
+
299
+ //#endregion
300
+ //#region src/injected/icon.ts
301
+ /**
302
+ * Generic Bitcoin wallet icon — same purse SVG style as the EVM
303
+ * package, recoloured. Inline so the picker doesn't flash.
304
+ *
305
+ * Lives in its own file because both injected adapters (UniSat-shape
306
+ * and sats-connect) need the same fallback when the wallet doesn't
307
+ * advertise its own icon, and there's no other "shared" thing they
308
+ * both want — a one-line module beats a grab-bag.
309
+ */
310
+ const GENERIC_BITCOIN_ICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2Y3OTMxYSIgc3Ryb2tlPSJub25lIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjx0ZXh0IHg9IjEyIiB5PSIxNyIgZm9udC1mYW1pbHk9InNlcmlmIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QjwvdGV4dD48L3N2Zz4=";
311
+
312
+ //#endregion
313
+ //#region src/injected/sats-connect.ts
314
+ const CAPS_SATS_CONNECT = {
315
+ getBalance: false,
316
+ getTransactionReceipt: false,
317
+ requestAccounts: true,
318
+ sendTransaction: true,
319
+ signIn: false,
320
+ signMessage: true,
321
+ signTransaction: true,
322
+ subscribe: false,
323
+ switchAccount: false,
324
+ switchChain: false
325
+ };
326
+ /**
327
+ * Wrap an Xverse-style `BitcoinProvider` (sats-connect) into a butr
328
+ * `WalletAdapter`. sats-connect routes everything through a single
329
+ * `request(method, params)` RPC; we shim each butr capability onto the
330
+ * corresponding sats-connect method.
331
+ *
332
+ * Tested against Xverse's `getAccounts`, `signMessage`, `signPsbt`,
333
+ * `sendTransfer` methods.
334
+ */
335
+ const buildSatsConnectAdapter = (id, name, provider) => {
336
+ let chain = BITCOIN_CHAINS.mainnet;
337
+ let cachedAccounts = [];
338
+ const callRequest = async (method, params) => {
339
+ const response = await provider.request(method, params);
340
+ if (response.error) throw new Error(`[butr/bitcoin] sats-connect ${method} failed: ${response.error.message}`);
341
+ return response.result;
342
+ };
343
+ const loadAccounts = async () => {
344
+ const result = await callRequest("getAccounts", {
345
+ message: "Connect to butr",
346
+ purposes: ["payment", "ordinals"]
347
+ });
348
+ if (!result?.addresses) return [];
349
+ const addresses = result.addresses.map((a) => a.address);
350
+ cachedAccounts = addresses;
351
+ return addresses;
352
+ };
353
+ return {
354
+ capabilities: CAPS_SATS_CONNECT,
355
+ chainPlatform: "bitcoin",
356
+ async connect() {
357
+ await loadAccounts();
358
+ },
359
+ disconnect() {
360
+ cachedAccounts = [];
361
+ return Promise.resolve();
362
+ },
363
+ async getAccount() {
364
+ const first = cachedAccounts[0];
365
+ if (first) return buildAccount(first, chain);
366
+ const firstFresh = (await loadAccounts())[0];
367
+ return firstFresh ? buildAccount(firstFresh, chain) : null;
368
+ },
369
+ async getAccounts() {
370
+ return (cachedAccounts.length > 0 ? cachedAccounts : await loadAccounts()).map((a) => buildAccount(a, chain));
371
+ },
372
+ getBalance() {
373
+ return Promise.resolve({
374
+ decimals: 8,
375
+ formatted: "0",
376
+ symbol: "BTC",
377
+ value: 0n
378
+ });
379
+ },
380
+ getSigner() {
381
+ return Promise.resolve(provider);
382
+ },
383
+ getTransactionReceipt() {
384
+ return Promise.resolve({ status: "Pending" });
385
+ },
386
+ icon: GENERIC_BITCOIN_ICON,
387
+ id,
388
+ name,
389
+ async requestAccounts() {
390
+ await loadAccounts();
391
+ },
392
+ async sendTx(tx) {
393
+ if (!tx || typeof tx !== "object" || typeof tx.recipient !== "string" || typeof tx.amount !== "bigint") throw new TypeError("Bitcoin sendTx expects { amount: bigint, recipient: string } — amount in satoshis");
394
+ const { amount, recipient } = tx;
395
+ return (await callRequest("sendTransfer", { recipients: [{
396
+ address: recipient,
397
+ amount: amount.toString()
398
+ }] })).txid;
399
+ },
400
+ sendTxToChain(tx, _targetChainId, _account, cb) {
401
+ cb?.();
402
+ return this.sendTx(tx);
403
+ },
404
+ async signMessage(msg) {
405
+ const address = cachedAccounts[0];
406
+ if (!address) throw new Error("No connected account");
407
+ return {
408
+ signature: base64ToBytes((await callRequest("signMessage", {
409
+ address,
410
+ message: new TextDecoder().decode(msg)
411
+ })).signature),
412
+ signedMessage: msg
413
+ };
414
+ },
415
+ async signTransaction(tx) {
416
+ if (!(tx instanceof Uint8Array)) throw new TypeError("Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())");
417
+ return base64ToBytes((await callRequest("signPsbt", { psbt: bytesToBase64(tx) })).psbt);
418
+ },
419
+ switchChain(target) {
420
+ if (target.namespace !== "bip122") throw new Error(`Bitcoin adapter received non-Bitcoin chain "${target.id}". Pass a chain with namespace "bip122".`);
421
+ chain = target;
422
+ return Promise.resolve();
423
+ }
424
+ };
425
+ };
426
+
427
+ //#endregion
428
+ //#region src/injected/unisat.ts
429
+ const CAPS_UNISAT = {
430
+ getBalance: false,
431
+ getTransactionReceipt: false,
432
+ requestAccounts: true,
433
+ sendTransaction: true,
434
+ signIn: false,
435
+ signMessage: true,
436
+ signTransaction: true,
437
+ subscribe: true,
438
+ switchAccount: false,
439
+ switchChain: false
440
+ };
441
+ /**
442
+ * Wrap a UniSat-style provider (`window.unisat`, `window.okxwallet.bitcoin`,
443
+ * `window.btc`) into a butr `WalletAdapter`.
444
+ *
445
+ * The UniSat shape is consistent enough that one adapter handles every
446
+ * derivative. Differences (network names, `sendBitcoin` presence) are
447
+ * gated by feature detection per call.
448
+ */
449
+ const buildUnisatAdapter = (id, name, provider) => {
450
+ let chain = BITCOIN_CHAINS.mainnet;
451
+ const listenersSet = /* @__PURE__ */ new Set();
452
+ const refreshChain = async () => {
453
+ if (typeof provider.getNetwork !== "function") return;
454
+ try {
455
+ const network = await provider.getNetwork();
456
+ if (network === "testnet") chain = BITCOIN_CHAINS.testnet;
457
+ else if (network === "signet") chain = BITCOIN_CHAINS.signet;
458
+ else chain = BITCOIN_CHAINS.mainnet;
459
+ } catch {}
460
+ };
461
+ return {
462
+ capabilities: CAPS_UNISAT,
463
+ chainPlatform: "bitcoin",
464
+ async connect(opts) {
465
+ if (opts?.silent) {
466
+ if ((await provider.getAccounts()).length === 0) throw new Error("No authorized accounts for silent reconnect");
467
+ await refreshChain();
468
+ return;
469
+ }
470
+ await provider.requestAccounts();
471
+ await refreshChain();
472
+ },
473
+ disconnect() {
474
+ return Promise.resolve();
475
+ },
476
+ async getAccount() {
477
+ const first = (await provider.getAccounts())[0];
478
+ if (!first) return null;
479
+ await refreshChain();
480
+ return buildAccount(first, chain);
481
+ },
482
+ async getAccounts() {
483
+ const accounts = await provider.getAccounts();
484
+ if (accounts.length === 0) return [];
485
+ await refreshChain();
486
+ return accounts.map((a) => buildAccount(a, chain));
487
+ },
488
+ getBalance() {
489
+ return Promise.resolve({
490
+ decimals: 8,
491
+ formatted: "0",
492
+ symbol: "BTC",
493
+ value: 0n
494
+ });
495
+ },
496
+ getSigner() {
497
+ return Promise.resolve(provider);
498
+ },
499
+ getTransactionReceipt() {
500
+ return Promise.resolve({ status: "Pending" });
501
+ },
502
+ icon: GENERIC_BITCOIN_ICON,
503
+ id,
504
+ name,
505
+ async requestAccounts() {
506
+ await provider.requestAccounts();
507
+ await refreshChain();
508
+ },
509
+ sendTx(tx) {
510
+ if (typeof provider.sendBitcoin !== "function") throw new TypeError(`Wallet ${name} does not expose sendBitcoin`);
511
+ if (!tx || typeof tx !== "object" || typeof tx.recipient !== "string" || typeof tx.amount !== "bigint") throw new TypeError("Bitcoin sendTx expects { amount: bigint, recipient: string } — amount in satoshis");
512
+ const { amount, recipient } = tx;
513
+ const sats = Number(amount);
514
+ return provider.sendBitcoin(recipient, sats);
515
+ },
516
+ sendTxToChain(tx, _targetChainIdDecimal, _account, cb) {
517
+ cb?.();
518
+ return this.sendTx(tx);
519
+ },
520
+ async signMessage(msg) {
521
+ const text = new TextDecoder().decode(msg);
522
+ return {
523
+ signature: base64ToBytes(await provider.signMessage(text)),
524
+ signedMessage: msg
525
+ };
526
+ },
527
+ async signTransaction(tx) {
528
+ if (!(tx instanceof Uint8Array)) throw new TypeError("Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())");
529
+ return hexToBytes(await provider.signPsbt(bytesToHex(tx)));
530
+ },
531
+ subscribe(listener) {
532
+ listenersSet.add(listener);
533
+ const onAccountsChanged = (...args) => {
534
+ const accounts = args[0] ?? [];
535
+ if (accounts.length === 0) {
536
+ listener({ type: "disconnected" });
537
+ return;
538
+ }
539
+ const built = accounts.map((a) => buildAccount(a, chain));
540
+ const first = built[0];
541
+ if (!first) return;
542
+ listener({
543
+ account: first,
544
+ accounts: built,
545
+ type: "accountChanged"
546
+ });
547
+ };
548
+ const onNetworkChanged = () => {
549
+ refreshChain();
550
+ };
551
+ provider.on?.("accountsChanged", onAccountsChanged);
552
+ provider.on?.("networkChanged", onNetworkChanged);
553
+ return () => {
554
+ provider.removeListener?.("accountsChanged", onAccountsChanged);
555
+ provider.removeListener?.("networkChanged", onNetworkChanged);
556
+ listenersSet.delete(listener);
557
+ };
558
+ },
559
+ switchChain(target) {
560
+ if (target.namespace !== "bip122") throw new Error(`Bitcoin adapter received non-Bitcoin chain "${target.id}". Pass a chain with namespace "bip122".`);
561
+ chain = target;
562
+ refreshChain();
563
+ return Promise.resolve();
564
+ }
565
+ };
566
+ };
567
+
568
+ //#endregion
569
+ //#region src/injected/index.ts
570
+ const DEFAULT_SETTLE_MS = 150;
571
+ const readHost = (target) => {
572
+ return target === void 0 ? typeof window === "undefined" ? null : window : target;
573
+ };
574
+ const probeProviders = (host) => {
575
+ const adapters = [];
576
+ const seen = /* @__PURE__ */ new Set();
577
+ if (host.unisat && !seen.has(host.unisat)) {
578
+ seen.add(host.unisat);
579
+ adapters.push(buildUnisatAdapter("injected:bitcoin:unisat", "Unisat", host.unisat));
580
+ }
581
+ const okxBitcoin = host.okxwallet?.bitcoin;
582
+ if (okxBitcoin && !seen.has(okxBitcoin)) {
583
+ seen.add(okxBitcoin);
584
+ adapters.push(buildUnisatAdapter("injected:bitcoin:okx", "OKX Wallet (Bitcoin)", okxBitcoin));
585
+ }
586
+ const xverse = host.XverseProviders?.BitcoinProvider;
587
+ if (xverse && !seen.has(xverse)) {
588
+ seen.add(xverse);
589
+ adapters.push(buildSatsConnectAdapter("injected:bitcoin:xverse", "Xverse", xverse));
590
+ }
591
+ if (host.btc && !seen.has(host.btc)) {
592
+ seen.add(host.btc);
593
+ adapters.push(buildUnisatAdapter("injected:bitcoin:legacy", "Browser Bitcoin wallet", host.btc));
594
+ }
595
+ return adapters;
596
+ };
597
+ /**
598
+ * Last-resort discovery path for Bitcoin wallets that DON'T announce via
599
+ * Wallet Standard. Probes, in order: `window.unisat`,
600
+ * `window.okxwallet.bitcoin`, `window.XverseProviders.BitcoinProvider`,
601
+ * `window.btc`.
602
+ *
603
+ * Wallet Standard wallets (Phantom, Magic Eden, Leather, modern OKX
604
+ * builds) are already handled by `discoverBitcoinAdapters`. This
605
+ * fallback waits `settleMs` (default 150ms), consults
606
+ * `hasAnyWalletStandardAdapter` if provided, and emits adapters for
607
+ * any injected providers that weren't already covered.
608
+ *
609
+ * Each emitted adapter has a stable id prefix (`injected:bitcoin:*`)
610
+ * so consumers can distinguish them in the picker UI.
611
+ */
612
+ const discoverInjectedBitcoinAdapter = (onAdapter, options = {}) => {
613
+ const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;
614
+ let cancelled = false;
615
+ const timer = setTimeout(() => {
616
+ if (cancelled) return;
617
+ if (options.hasAnyWalletStandardAdapter?.()) return;
618
+ const host = readHost(options.target);
619
+ if (!host) return;
620
+ const adapters = probeProviders(host);
621
+ for (const adapter of adapters) onAdapter(adapter);
622
+ }, settleMs);
623
+ return () => {
624
+ cancelled = true;
625
+ clearTimeout(timer);
626
+ };
627
+ };
628
+
629
+ //#endregion
630
+ //#region src/discoverer.ts
631
+ /**
632
+ * Bitcoin's `PlatformDiscoverer`: Wallet Standard primary (Phantom,
633
+ * Magic Eden, Leather, OKX); legacy fallback covers sats-connect
634
+ * (Xverse), `window.unisat`, OKX legacy, and `window.btc`. The
635
+ * fallback defers to Wallet Standard via `hasAnyPrimaryAdapter`.
636
+ */
637
+ const bitcoinDiscoverer = {
638
+ fallback: { subscribe: (onAdapter, opts) => discoverInjectedBitcoinAdapter(onAdapter, { hasAnyWalletStandardAdapter: opts.hasAnyPrimaryAdapter }) },
639
+ platform: "bitcoin",
640
+ subscribe: discoverBitcoinAdapters
641
+ };
642
+
643
+ //#endregion
644
+ export { BITCOIN_CHAINS, BITCOIN_CHAINS_LIST, GENERIC_BITCOIN_ICON, bitcoinDiscoverer, buildBitcoinAdapter, discoverBitcoinAdapters, discoverInjectedBitcoinAdapter, resolveBitcoinCapabilities, slugify };
2
645
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["kitSlugify","base64ToBytes"],"sources":["../src/capabilities.ts","../src/wallet-standard-adapter.ts","../src/wallet-standard.ts","../src/chains.ts","../src/injected/icon.ts","../src/injected/sats-connect.ts","../src/injected/unisat.ts","../src/injected/index.ts","../src/discoverer.ts"],"sourcesContent":["import type { WalletCapabilities } from \"@usebutr/core\";\n\ntype BitcoinCapabilityInput = {\n chainCount: number;\n features: {\n events: boolean;\n sendTransfer: boolean;\n signMessage: boolean;\n signPsbt: boolean;\n };\n};\n\n/**\n * Bitcoin capability mapping.\n *\n * - `sendTransaction = bitcoin:sendTransfer present`. The wallet handles\n * UTXO selection, fee estimation, signing, and broadcast.\n * - `signTransaction = bitcoin:signPsbt present`. Sign-only PSBT path\n * for consumers that build their own UTXO-shaped transactions with\n * `bitcoinjs-lib` and broadcast through their own provider.\n * - `signMessage = bitcoin:signMessage present`.\n * - `signIn = false`. No Sign-In-With-Bitcoin standard yet (BIP-322 is\n * message-signing oriented, not auth).\n * - `subscribe = events present`. Most Bitcoin wallets don't emit\n * change events portably; capabilities admits the truth.\n * - `switchChain = false`. No portable per-call switch RPC across\n * Bitcoin wallets — Xverse/Unisat/Phantom each pick their own network.\n */\nconst resolveBitcoinCapabilities = (input: BitcoinCapabilityInput): WalletCapabilities => ({\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: false,\n sendTransaction: input.features.sendTransfer,\n signIn: false,\n signMessage: input.features.signMessage,\n signTransaction: input.features.signPsbt,\n subscribe: input.features.events,\n switchAccount: false,\n switchChain: input.chainCount > 1,\n});\n\nexport type { BitcoinCapabilityInput };\nexport { resolveBitcoinCapabilities };\n","import type { Account, ChainBase, ConnectorEvent, WalletAdapter } from \"@usebutr/core\";\nimport { logWarn, sanitizeIcon } from \"@usebutr/core\";\nimport {\n buildAccount,\n getFeature,\n pickAccountByAddress,\n pickFirstAddress,\n slugify as kitSlugify,\n} from \"@usebutr/wallet-standard-shared\";\nimport type {\n StandardConnectFeature,\n StandardDisconnectFeature,\n StandardEventsFeature,\n WalletStandardWallet,\n} from \"@usebutr/wallet-standard-shared\";\n\nimport { resolveBitcoinCapabilities } from \"./capabilities\";\nimport type {\n BitcoinSendTransferFeature,\n BitcoinSignMessageFeature,\n BitcoinSignPsbtFeature,\n} from \"./wallet-standard-types\";\n\nconst BITCOIN_PREFIX = \"bip122:\";\nconst BITCOIN_DECIMALS = 8;\nconst BITCOIN_MAINNET_ID = \"bip122:000000000019d6689c085ae165831e93\";\n\nconst slugify = (name: string): string => kitSlugify(\"btc\", name);\n\nconst pickBitcoinChain = (wallet: WalletStandardWallet): string | null => {\n const mainnet = wallet.chains.find((c) => c === BITCOIN_MAINNET_ID);\n if (mainnet) {\n return mainnet;\n }\n return wallet.chains.find((c) => c.startsWith(BITCOIN_PREFIX)) ?? null;\n};\n\nconst buildBitcoinChain = (chainId: string, walletName: string): ChainBase => ({\n id: chainId,\n // Same posture as EVM/SVM/Sui: butr ships no chain-id → name table.\n name: walletName,\n namespace: \"bip122\",\n reference: chainId.slice(BITCOIN_PREFIX.length),\n});\n\nconst buildBitcoinAccount = (address: string, chain: ChainBase): Account =>\n buildAccount(address, chain);\n\n/**\n * Adapt a Bitcoin Wallet Standard `Wallet` into a butr `WalletAdapter`.\n *\n * Returns `null` if the wallet doesn't advertise any `bip122:` chain or\n * doesn't expose `standard:connect`. Same posture as the SVM/Sui\n * adapters: gate features on what each wallet advertises, return\n * placeholders for RPC reads, forward `subscribe` through\n * `standard:events`.\n *\n * **Known limitations**\n *\n * - `getBalance` returns `{ value: 0n, symbol: \"BTC\" }`. Bitcoin\n * balance lookups require an Esplora/Electrum/RPC client outside\n * butr's scope.\n * - `getTransactionReceipt` returns `\"Pending\"` for the same reason.\n * - `sendTx` expects the consumer to pass `{ amount: bigint, recipient: string }`\n * via butr's `unknown` tx parameter — the simplest mental model that\n * maps onto `bitcoin:sendTransfer`. PSBT-shaped flows go through\n * `signTransaction`.\n * - `signTransaction` expects a `Uint8Array` PSBT (raw bytes) — the\n * same shape `bitcoin:signPsbt` accepts. Consumers building with\n * `bitcoinjs-lib` get bytes via `psbt.toBuffer()`.\n * - `switchChain` is local-state-only; the capability flag is `false`\n * when only one chain is advertised. Wallets that ship a real switch\n * primitive (none today, portably) would need their own adapter.\n */\nconst buildBitcoinAdapter = (\n wallet: WalletStandardWallet,\n /** Optional. Called with a function that pushes a synthetic\n * `disconnected` event to all current subscribers. The discovery\n * layer invokes it on Wallet Standard `unregister`. */\n registerDisconnector?: (emit: () => void) => void,\n): WalletAdapter | null => {\n const bitcoinChainId = pickBitcoinChain(wallet);\n if (!bitcoinChainId) {\n return null;\n }\n const connect = getFeature<StandardConnectFeature>(wallet, \"standard:connect\");\n if (!connect) {\n return null;\n }\n\n const disconnect = getFeature<StandardDisconnectFeature>(wallet, \"standard:disconnect\");\n const events = getFeature<StandardEventsFeature>(wallet, \"standard:events\");\n const signMessage = getFeature<BitcoinSignMessageFeature>(wallet, \"bitcoin:signMessage\");\n const signPsbt = getFeature<BitcoinSignPsbtFeature>(wallet, \"bitcoin:signPsbt\");\n const sendTransfer = getFeature<BitcoinSendTransferFeature>(wallet, \"bitcoin:sendTransfer\");\n\n let currentChainId = bitcoinChainId;\n const currentChain = (): ChainBase => buildBitcoinChain(currentChainId, wallet.name);\n\n const listeners = new Set<(event: ConnectorEvent) => void>();\n const notifyAccountChanged = () => {\n if (wallet.accounts.length === 0) {\n return;\n }\n const chain = currentChain();\n const built = wallet.accounts.map((a) => buildBitcoinAccount(a.address, chain));\n const first = built[0];\n if (!first) {\n return;\n }\n for (const listener of listeners) {\n listener({ account: first, accounts: built, type: \"accountChanged\" });\n }\n };\n\n registerDisconnector?.(() => {\n for (const listener of listeners) {\n listener({ type: \"disconnected\" });\n }\n });\n\n return {\n capabilities: resolveBitcoinCapabilities({\n chainCount: wallet.chains.filter((c) => c.startsWith(BITCOIN_PREFIX)).length,\n features: {\n events: Boolean(events),\n sendTransfer: Boolean(sendTransfer),\n signMessage: Boolean(signMessage),\n signPsbt: Boolean(signPsbt),\n },\n }),\n chainPlatform: \"bitcoin\",\n\n async connect(opts) {\n await connect.connect(opts?.silent ? { silent: true } : undefined);\n },\n\n async disconnect() {\n if (disconnect) {\n try {\n await disconnect.disconnect();\n } catch (error) {\n logWarn(\"[butr] Bitcoin Wallet Standard disconnect threw:\", error);\n }\n }\n },\n\n getAccount() {\n const address = pickFirstAddress(wallet.accounts);\n if (!address) {\n return Promise.resolve(null);\n }\n return Promise.resolve(buildBitcoinAccount(address, currentChain()));\n },\n\n getAccounts() {\n const chain = currentChain();\n return Promise.resolve(wallet.accounts.map((a) => buildBitcoinAccount(a.address, chain)));\n },\n\n getBalance() {\n return Promise.resolve({\n decimals: BITCOIN_DECIMALS,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n });\n },\n\n getSigner() {\n // Consumers cast to whatever Bitcoin signing wrapper they use\n // (bitcoinjs-lib's Signer, scure-btc-signer's HDWallet, etc.) or\n // call butr's adapter directly for PSBT / send-transfer.\n return Promise.resolve(wallet);\n },\n\n getTransactionReceipt() {\n return Promise.resolve({ status: \"Pending\" as const });\n },\n\n icon: sanitizeIcon(wallet.icon),\n id: slugify(wallet.name),\n name: wallet.name,\n\n async requestAccounts() {\n await connect.connect();\n },\n\n async sendTx(tx, account) {\n if (!sendTransfer) {\n throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:sendTransfer`);\n }\n if (\n !tx ||\n typeof tx !== \"object\" ||\n typeof (tx as { amount?: unknown }).amount !== \"bigint\" ||\n typeof (tx as { recipient?: unknown }).recipient !== \"string\"\n ) {\n throw new TypeError(\n \"Bitcoin sendTx expects { amount: bigint, recipient: string } — pass the recipient address and an amount in satoshis\",\n );\n }\n const { amount, recipient } = tx as { amount: bigint; recipient: string };\n const wsAccount = account\n ? pickAccountByAddress(wallet.accounts, account.walletAddress)\n : (wallet.accounts[0] ?? null);\n if (!wsAccount) {\n throw new Error(\"No connected account\");\n }\n const output = await sendTransfer.sendTransfer({\n account: wsAccount,\n amount,\n chain: currentChainId,\n recipient,\n });\n return output.txid;\n },\n\n sendTxToChain(tx, _targetChainId, account, cb) {\n cb?.();\n return this.sendTx(tx, account);\n },\n\n async signMessage(msg, account) {\n if (!signMessage) {\n throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:signMessage`);\n }\n const wsAccount = account\n ? pickAccountByAddress(wallet.accounts, account.walletAddress)\n : (wallet.accounts[0] ?? null);\n if (!wsAccount) {\n throw new Error(\"No connected account\");\n }\n const output = await signMessage.signMessage({ account: wsAccount, message: msg });\n return { signature: output.signature, signedMessage: output.signedMessage };\n },\n\n ...(signPsbt\n ? {\n async signTransaction(tx, account) {\n const wsAccount = account\n ? pickAccountByAddress(wallet.accounts, account.walletAddress)\n : (wallet.accounts[0] ?? null);\n if (!wsAccount) {\n throw new Error(\"No connected account\");\n }\n if (!(tx instanceof Uint8Array)) {\n throw new TypeError(\n \"Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())\",\n );\n }\n const output = await signPsbt.signPsbt({\n account: wsAccount,\n chain: currentChainId,\n psbt: tx,\n });\n return output.signedPsbt;\n },\n }\n : {}),\n\n subscribe(listener) {\n listeners.add(listener);\n let unsubWallet: (() => void) | null = null;\n if (events) {\n const unsub = events.on(\"change\", (changes) => {\n if (changes.chains) {\n const next =\n changes.chains.find((c) => c === BITCOIN_MAINNET_ID) ??\n changes.chains.find((c) => c.startsWith(BITCOIN_PREFIX));\n if (next) {\n currentChainId = next;\n }\n }\n\n if (changes.accounts) {\n if (changes.accounts.length === 0) {\n listener({ type: \"disconnected\" });\n return;\n }\n const chain = currentChain();\n const built = changes.accounts.map((a) => buildBitcoinAccount(a.address, chain));\n const first = built[0];\n if (!first) {\n return;\n }\n listener({ account: first, accounts: built, type: \"accountChanged\" });\n return;\n }\n\n if (changes.chains) {\n notifyAccountChanged();\n }\n });\n unsubWallet = () => unsub();\n }\n return () => {\n listeners.delete(listener);\n unsubWallet?.();\n };\n },\n\n switchChain(chain) {\n if (chain.namespace !== \"bip122\") {\n throw new Error(\n `Bitcoin adapter received non-Bitcoin chain \"${chain.id}\". Pass a chain with namespace \"bip122\".`,\n );\n }\n if (!wallet.chains.includes(chain.id)) {\n throw new Error(\n `Wallet ${wallet.name} does not advertise chain \"${chain.id}\". Available: ${wallet.chains.join(\", \")}`,\n );\n }\n currentChainId = chain.id;\n notifyAccountChanged();\n return Promise.resolve();\n },\n };\n};\n\nexport { buildBitcoinAdapter, slugify };\n","import type { WalletAdapter } from \"@usebutr/core\";\nimport { discoverWalletStandard } from \"@usebutr/wallet-standard-shared\";\n\nimport { buildBitcoinAdapter } from \"./wallet-standard-adapter\";\n\n/**\n * Subscribe to Bitcoin Wallet Standard announcements.\n *\n * Phantom (Bitcoin), Magic Eden, OKX Wallet (Bitcoin), and Leather\n * advertise `bitcoin:*` features over the same `getWallets()` bus that\n * SVM and Sui consume. `buildBitcoinAdapter` returns `null` for wallets\n * that don't advertise any `bip122:` chain, so multi-chain wallets\n * (Phantom: EVM + SVM + Sui + Bitcoin) produce one adapter per platform.\n *\n * Requires the **optional peer dependency** `@wallet-standard/app`.\n *\n * The discovery loop (dynamic import, dedupe, register / unregister\n * bridge) lives in `@usebutr/wallet-standard-shared`.\n */\nconst discoverBitcoinAdapters = (onAdapter: (adapter: WalletAdapter) => void): (() => void) =>\n discoverWalletStandard(onAdapter, (wallet, registerDisconnector) =>\n buildBitcoinAdapter(wallet, registerDisconnector),\n );\n\nexport { discoverBitcoinAdapters };\n","import type { ChainBase } from \"@usebutr/core\";\n\n/**\n * CAIP-2 Bitcoin chain references use the first 8 bytes (big-endian)\n * of each network's genesis block hash. These string ids are what\n * Bitcoin Wallet Standard wallets (Phantom, Magic Eden, OKX) advertise\n * in `wallet.chains`; the adapter's `switchChain` rejects anything else.\n *\n * - Mainnet: `bip122:000000000019d6689c085ae165831e93`\n * - Testnet: `bip122:000000000933ea01ad0ee984209779ba`\n * - Signet: `bip122:00000008819873e925422c1ff0f99f7c`\n *\n * Bitcoin has no per-call \"switch chain\" RPC across the major wallets,\n * so butr's adapter treats chain as a wallet-side configuration —\n * `switchChain` updates local state to influence subsequent calls (same\n * posture as SVM). Bitcoin's `switchChain` capability is `false` by\n * default; consumers building on top can opt in if their wallet exposes\n * a switch primitive.\n */\nconst BITCOIN_CHAINS = {\n mainnet: {\n id: \"bip122:000000000019d6689c085ae165831e93\",\n name: \"Bitcoin\",\n namespace: \"bip122\",\n reference: \"000000000019d6689c085ae165831e93\",\n },\n signet: {\n id: \"bip122:00000008819873e925422c1ff0f99f7c\",\n name: \"Bitcoin Signet\",\n namespace: \"bip122\",\n reference: \"00000008819873e925422c1ff0f99f7c\",\n },\n testnet: {\n id: \"bip122:000000000933ea01ad0ee984209779ba\",\n name: \"Bitcoin Testnet\",\n namespace: \"bip122\",\n reference: \"000000000933ea01ad0ee984209779ba\",\n },\n} as const satisfies Record<string, ChainBase>;\n\nconst BITCOIN_CHAINS_LIST: ReadonlyArray<ChainBase> = Object.values(BITCOIN_CHAINS);\n\nexport { BITCOIN_CHAINS, BITCOIN_CHAINS_LIST };\n","/**\n * Generic Bitcoin wallet icon — same purse SVG style as the EVM\n * package, recoloured. Inline so the picker doesn't flash.\n *\n * Lives in its own file because both injected adapters (UniSat-shape\n * and sats-connect) need the same fallback when the wallet doesn't\n * advertise its own icon, and there's no other \"shared\" thing they\n * both want — a one-line module beats a grab-bag.\n */\nconst GENERIC_BITCOIN_ICON =\n \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2Y3OTMxYSIgc3Ryb2tlPSJub25lIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjx0ZXh0IHg9IjEyIiB5PSIxNyIgZm9udC1mYW1pbHk9InNlcmlmIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QjwvdGV4dD48L3N2Zz4=\";\n\nexport { GENERIC_BITCOIN_ICON };\n","import type { ChainBase, WalletAdapter, WalletCapabilities } from \"@usebutr/core\";\nimport { buildAccount } from \"@usebutr/wallet-standard-shared\";\n\nimport { BITCOIN_CHAINS } from \"../chains\";\n\nimport { GENERIC_BITCOIN_ICON } from \"./icon\";\n\n/** sats-connect (Xverse) shape — a JSON-RPC-ish `request(method, params)`. */\ntype SatsConnectProvider = {\n request(\n method: string,\n params?: Record<string, unknown>,\n ): Promise<{ error?: { message: string }; result?: unknown }>;\n};\n\nconst CAPS_SATS_CONNECT: WalletCapabilities = {\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: true,\n sendTransaction: true,\n signIn: false,\n signMessage: true,\n signTransaction: true,\n subscribe: false,\n switchAccount: false,\n switchChain: false,\n};\n\n// Encoding helpers — small enough to live next to their caller rather\n// than in a cross-cutting \"shared\" file.\nconst base64ToBytes = (b64: string): Uint8Array => {\n const binary = atob(b64);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) {\n out[i] = binary.codePointAt(i) ?? 0;\n }\n return out;\n};\n\nconst bytesToBase64 = (bytes: Uint8Array): string => {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCodePoint(byte);\n }\n return btoa(binary);\n};\n\n/**\n * Wrap an Xverse-style `BitcoinProvider` (sats-connect) into a butr\n * `WalletAdapter`. sats-connect routes everything through a single\n * `request(method, params)` RPC; we shim each butr capability onto the\n * corresponding sats-connect method.\n *\n * Tested against Xverse's `getAccounts`, `signMessage`, `signPsbt`,\n * `sendTransfer` methods.\n */\nconst buildSatsConnectAdapter = (\n id: string,\n name: string,\n provider: SatsConnectProvider,\n): WalletAdapter => {\n let chain: ChainBase = BITCOIN_CHAINS.mainnet;\n let cachedAccounts: ReadonlyArray<string> = [];\n\n const callRequest = async <T>(method: string, params?: Record<string, unknown>): Promise<T> => {\n const response = await provider.request(method, params);\n if (response.error) {\n throw new Error(`[butr/bitcoin] sats-connect ${method} failed: ${response.error.message}`);\n }\n return response.result as T;\n };\n\n const loadAccounts = async (): Promise<ReadonlyArray<string>> => {\n const result = await callRequest<{\n addresses?: ReadonlyArray<{ address: string; purpose?: string }>;\n }>(\"getAccounts\", {\n message: \"Connect to butr\",\n purposes: [\"payment\", \"ordinals\"],\n });\n if (!result?.addresses) {\n return [];\n }\n const addresses = result.addresses.map((a) => a.address);\n cachedAccounts = addresses;\n return addresses;\n };\n\n return {\n capabilities: CAPS_SATS_CONNECT,\n chainPlatform: \"bitcoin\",\n\n async connect() {\n await loadAccounts();\n },\n\n disconnect() {\n cachedAccounts = [];\n return Promise.resolve();\n },\n\n async getAccount() {\n const first = cachedAccounts[0];\n if (first) {\n return buildAccount(first, chain);\n }\n const accounts = await loadAccounts();\n const firstFresh = accounts[0];\n return firstFresh ? buildAccount(firstFresh, chain) : null;\n },\n\n async getAccounts() {\n const accounts = cachedAccounts.length > 0 ? cachedAccounts : await loadAccounts();\n return accounts.map((a) => buildAccount(a, chain));\n },\n\n getBalance() {\n return Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n });\n },\n\n getSigner() {\n return Promise.resolve(provider);\n },\n\n getTransactionReceipt() {\n return Promise.resolve({ status: \"Pending\" as const });\n },\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n async requestAccounts() {\n await loadAccounts();\n },\n\n async sendTx(tx) {\n if (\n !tx ||\n typeof tx !== \"object\" ||\n typeof (tx as { recipient?: unknown }).recipient !== \"string\" ||\n typeof (tx as { amount?: unknown }).amount !== \"bigint\"\n ) {\n throw new TypeError(\n \"Bitcoin sendTx expects { amount: bigint, recipient: string } — amount in satoshis\",\n );\n }\n const { amount, recipient } = tx as { amount: bigint; recipient: string };\n const result = await callRequest<{ txid: string }>(\"sendTransfer\", {\n recipients: [{ address: recipient, amount: amount.toString() }],\n });\n return result.txid;\n },\n\n sendTxToChain(tx, _targetChainId, _account, cb) {\n cb?.();\n return this.sendTx(tx);\n },\n\n async signMessage(msg) {\n const address = cachedAccounts[0];\n if (!address) {\n throw new Error(\"No connected account\");\n }\n const result = await callRequest<{ messageHash?: string; signature: string }>(\"signMessage\", {\n address,\n message: new TextDecoder().decode(msg),\n });\n return { signature: base64ToBytes(result.signature), signedMessage: msg };\n },\n\n async signTransaction(tx) {\n if (!(tx instanceof Uint8Array)) {\n throw new TypeError(\n \"Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())\",\n );\n }\n // sats-connect's signPsbt takes a base64 PSBT; encode our bytes\n // and decode the response back to bytes.\n const result = await callRequest<{ psbt: string }>(\"signPsbt\", {\n psbt: bytesToBase64(tx),\n });\n return base64ToBytes(result.psbt);\n },\n\n switchChain(target) {\n if (target.namespace !== \"bip122\") {\n throw new Error(\n `Bitcoin adapter received non-Bitcoin chain \"${target.id}\". Pass a chain with namespace \"bip122\".`,\n );\n }\n chain = target;\n return Promise.resolve();\n },\n };\n};\n\nexport type { SatsConnectProvider };\nexport { buildSatsConnectAdapter };\n","import type { ChainBase, ConnectorEvent, WalletAdapter, WalletCapabilities } from \"@usebutr/core\";\nimport { buildAccount } from \"@usebutr/wallet-standard-shared\";\n\nimport { BITCOIN_CHAINS } from \"../chains\";\n\nimport { GENERIC_BITCOIN_ICON } from \"./icon\";\n\n/** UniSat-style provider: a single object on `window.unisat` with the\n * same four methods every UniSat-derivative wallet exposes (UniSat\n * itself, OKX Wallet's Bitcoin path at `window.okxwallet.bitcoin`). */\ntype UnisatProvider = {\n getAccounts(): Promise<ReadonlyArray<string>>;\n getNetwork?(): Promise<\"livenet\" | \"mainnet\" | \"testnet\" | \"signet\">;\n on?(\n event: \"accountsChanged\" | \"networkChanged\",\n listener: (...args: Array<unknown>) => void,\n ): void;\n pushPsbt?(psbtHex: string): Promise<string>;\n removeListener?(\n event: \"accountsChanged\" | \"networkChanged\",\n listener: (...args: Array<unknown>) => void,\n ): void;\n requestAccounts(): Promise<ReadonlyArray<string>>;\n sendBitcoin?(recipient: string, amount: number): Promise<string>;\n signMessage(message: string, type?: \"ecdsa\" | \"bip322-simple\"): Promise<string>;\n signPsbt(psbtHex: string, options?: Record<string, unknown>): Promise<string>;\n};\n\nconst CAPS_UNISAT: WalletCapabilities = {\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: true,\n sendTransaction: true,\n signIn: false,\n signMessage: true,\n signTransaction: true,\n subscribe: true,\n switchAccount: false,\n switchChain: false,\n};\n\n// Encoding helpers — small enough to live next to their caller rather\n// than in a cross-cutting \"shared\" file.\nconst bytesToHex = (bytes: Uint8Array): string => {\n let hex = \"\";\n for (const byte of bytes) {\n hex += byte.toString(16).padStart(2, \"0\");\n }\n return hex;\n};\n\nconst hexToBytes = (hex: string): Uint8Array => {\n const clean = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n const out = new Uint8Array(clean.length / 2);\n for (let i = 0; i < out.length; i += 1) {\n out[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n};\n\nconst base64ToBytes = (b64: string): Uint8Array => {\n const binary = atob(b64);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) {\n out[i] = binary.codePointAt(i) ?? 0;\n }\n return out;\n};\n\n/**\n * Wrap a UniSat-style provider (`window.unisat`, `window.okxwallet.bitcoin`,\n * `window.btc`) into a butr `WalletAdapter`.\n *\n * The UniSat shape is consistent enough that one adapter handles every\n * derivative. Differences (network names, `sendBitcoin` presence) are\n * gated by feature detection per call.\n */\nconst buildUnisatAdapter = (id: string, name: string, provider: UnisatProvider): WalletAdapter => {\n let chain: ChainBase = BITCOIN_CHAINS.mainnet;\n const listenersSet = new Set<(event: ConnectorEvent) => void>();\n\n const refreshChain = async () => {\n if (typeof provider.getNetwork !== \"function\") {\n return;\n }\n try {\n const network = await provider.getNetwork();\n if (network === \"testnet\") {\n chain = BITCOIN_CHAINS.testnet;\n } else if (network === \"signet\") {\n chain = BITCOIN_CHAINS.signet;\n } else {\n chain = BITCOIN_CHAINS.mainnet;\n }\n } catch {\n // Network probe failed — keep the current chain. The next call\n // will retry through whichever path next invokes refreshChain.\n }\n };\n\n return {\n capabilities: CAPS_UNISAT,\n chainPlatform: \"bitcoin\",\n\n async connect(opts) {\n if (opts?.silent) {\n const accounts = await provider.getAccounts();\n if (accounts.length === 0) {\n throw new Error(\"No authorized accounts for silent reconnect\");\n }\n await refreshChain();\n return;\n }\n await provider.requestAccounts();\n await refreshChain();\n },\n\n disconnect() {\n // No portable disconnect across UniSat-shaped wallets. butr's\n // reducer marks the wallet disconnected on its side regardless.\n return Promise.resolve();\n },\n\n async getAccount() {\n const accounts = await provider.getAccounts();\n const first = accounts[0];\n if (!first) {\n return null;\n }\n await refreshChain();\n return buildAccount(first, chain);\n },\n\n async getAccounts() {\n const accounts = await provider.getAccounts();\n if (accounts.length === 0) {\n return [];\n }\n await refreshChain();\n return accounts.map((a) => buildAccount(a, chain));\n },\n\n getBalance() {\n return Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n });\n },\n\n getSigner() {\n return Promise.resolve(provider);\n },\n\n getTransactionReceipt() {\n return Promise.resolve({ status: \"Pending\" as const });\n },\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n async requestAccounts() {\n await provider.requestAccounts();\n await refreshChain();\n },\n\n sendTx(tx) {\n if (typeof provider.sendBitcoin !== \"function\") {\n throw new TypeError(`Wallet ${name} does not expose sendBitcoin`);\n }\n if (\n !tx ||\n typeof tx !== \"object\" ||\n typeof (tx as { recipient?: unknown }).recipient !== \"string\" ||\n typeof (tx as { amount?: unknown }).amount !== \"bigint\"\n ) {\n throw new TypeError(\n \"Bitcoin sendTx expects { amount: bigint, recipient: string } — amount in satoshis\",\n );\n }\n const { amount, recipient } = tx as { amount: bigint; recipient: string };\n // UniSat's sendBitcoin takes a JS number for satoshis. Values\n // above 2^53 aren't representable; that's 90+ million BTC, which\n // would never appear in practice.\n const sats = Number(amount);\n return provider.sendBitcoin(recipient, sats);\n },\n\n sendTxToChain(tx, _targetChainIdDecimal, _account, cb) {\n cb?.();\n return this.sendTx(tx);\n },\n\n async signMessage(msg) {\n // UniSat takes a UTF-8 message and returns a base64 signature.\n // We return the raw signature bytes (decoded from base64) and the\n // bytes the wallet signed (pass-through of the input). UniSat\n // doesn't expose a \"pre-image\" so the input itself is the signed\n // message from butr's perspective.\n const text = new TextDecoder().decode(msg);\n const signatureB64 = await provider.signMessage(text);\n return { signature: base64ToBytes(signatureB64), signedMessage: msg };\n },\n\n async signTransaction(tx) {\n if (!(tx instanceof Uint8Array)) {\n throw new TypeError(\n \"Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())\",\n );\n }\n const signedHex = await provider.signPsbt(bytesToHex(tx));\n return hexToBytes(signedHex);\n },\n\n subscribe(listener) {\n listenersSet.add(listener);\n const onAccountsChanged = (...args: ReadonlyArray<unknown>) => {\n const accounts = (args[0] as ReadonlyArray<string> | undefined) ?? [];\n if (accounts.length === 0) {\n listener({ type: \"disconnected\" });\n return;\n }\n const built = accounts.map((a) => buildAccount(a, chain));\n const first = built[0];\n if (!first) {\n return;\n }\n listener({ account: first, accounts: built, type: \"accountChanged\" });\n };\n const onNetworkChanged = () => {\n void refreshChain();\n };\n provider.on?.(\"accountsChanged\", onAccountsChanged);\n provider.on?.(\"networkChanged\", onNetworkChanged);\n return () => {\n provider.removeListener?.(\"accountsChanged\", onAccountsChanged);\n provider.removeListener?.(\"networkChanged\", onNetworkChanged);\n listenersSet.delete(listener);\n };\n },\n\n switchChain(target) {\n if (target.namespace !== \"bip122\") {\n throw new Error(\n `Bitcoin adapter received non-Bitcoin chain \"${target.id}\". Pass a chain with namespace \"bip122\".`,\n );\n }\n // UniSat-shaped wallets pick their network via the user's\n // extension UI; we update local state so consumers see it, but\n // the wallet itself doesn't switch.\n chain = target;\n void refreshChain();\n return Promise.resolve();\n },\n };\n};\n\nexport type { UnisatProvider };\nexport { buildUnisatAdapter };\n","import type { WalletAdapter } from \"@usebutr/core\";\n\nimport { GENERIC_BITCOIN_ICON } from \"./icon\";\nimport type { SatsConnectProvider } from \"./sats-connect\";\nimport { buildSatsConnectAdapter } from \"./sats-connect\";\nimport type { UnisatProvider } from \"./unisat\";\nimport { buildUnisatAdapter } from \"./unisat\";\n\nconst DEFAULT_SETTLE_MS = 150;\n\ntype InjectedHost = {\n btc?: UnisatProvider;\n okxwallet?: { bitcoin?: UnisatProvider };\n unisat?: UnisatProvider;\n XverseProviders?: { BitcoinProvider?: SatsConnectProvider };\n};\n\ntype InjectedBitcoinDiscoveryOptions = {\n /** Suppresses emission when Wallet Standard discovery has already\n * registered a Bitcoin adapter for the same browser session. */\n hasAnyWalletStandardAdapter?: () => boolean;\n /** Settle deadline in ms before the fallback fires. Same default and\n * intent as the EVM injected fallback. */\n settleMs?: number;\n /** Override the global host (tests, iframes). */\n target?: InjectedHost | null;\n};\n\nconst readHost = (target: InjectedBitcoinDiscoveryOptions[\"target\"]): InjectedHost | null => {\n const globalWindow = typeof window === \"undefined\" ? null : (window as unknown as InjectedHost);\n return target === undefined ? globalWindow : target;\n};\n\nconst probeProviders = (host: InjectedHost): Array<WalletAdapter> => {\n const adapters: Array<WalletAdapter> = [];\n const seen = new Set<UnisatProvider | SatsConnectProvider>();\n\n if (host.unisat && !seen.has(host.unisat)) {\n seen.add(host.unisat);\n adapters.push(buildUnisatAdapter(\"injected:bitcoin:unisat\", \"Unisat\", host.unisat));\n }\n\n const okxBitcoin = host.okxwallet?.bitcoin;\n if (okxBitcoin && !seen.has(okxBitcoin)) {\n seen.add(okxBitcoin);\n adapters.push(buildUnisatAdapter(\"injected:bitcoin:okx\", \"OKX Wallet (Bitcoin)\", okxBitcoin));\n }\n\n const xverse = host.XverseProviders?.BitcoinProvider;\n if (xverse && !seen.has(xverse)) {\n seen.add(xverse);\n adapters.push(buildSatsConnectAdapter(\"injected:bitcoin:xverse\", \"Xverse\", xverse));\n }\n\n if (host.btc && !seen.has(host.btc)) {\n seen.add(host.btc);\n adapters.push(\n buildUnisatAdapter(\"injected:bitcoin:legacy\", \"Browser Bitcoin wallet\", host.btc),\n );\n }\n\n return adapters;\n};\n\n/**\n * Last-resort discovery path for Bitcoin wallets that DON'T announce via\n * Wallet Standard. Probes, in order: `window.unisat`,\n * `window.okxwallet.bitcoin`, `window.XverseProviders.BitcoinProvider`,\n * `window.btc`.\n *\n * Wallet Standard wallets (Phantom, Magic Eden, Leather, modern OKX\n * builds) are already handled by `discoverBitcoinAdapters`. This\n * fallback waits `settleMs` (default 150ms), consults\n * `hasAnyWalletStandardAdapter` if provided, and emits adapters for\n * any injected providers that weren't already covered.\n *\n * Each emitted adapter has a stable id prefix (`injected:bitcoin:*`)\n * so consumers can distinguish them in the picker UI.\n */\nconst discoverInjectedBitcoinAdapter = (\n onAdapter: (adapter: WalletAdapter) => void,\n options: InjectedBitcoinDiscoveryOptions = {},\n): (() => void) => {\n const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;\n let cancelled = false;\n const timer = setTimeout(() => {\n if (cancelled) {\n return;\n }\n if (options.hasAnyWalletStandardAdapter?.()) {\n return;\n }\n const host = readHost(options.target);\n if (!host) {\n return;\n }\n const adapters = probeProviders(host);\n for (const adapter of adapters) {\n onAdapter(adapter);\n }\n }, settleMs);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n};\n\nexport type { InjectedBitcoinDiscoveryOptions };\nexport { GENERIC_BITCOIN_ICON, discoverInjectedBitcoinAdapter };\n","import type { PlatformDiscoverer } from \"@usebutr/core\";\n\nimport { discoverInjectedBitcoinAdapter } from \"./injected\";\nimport { discoverBitcoinAdapters } from \"./wallet-standard\";\n\n/**\n * Bitcoin's `PlatformDiscoverer`: Wallet Standard primary (Phantom,\n * Magic Eden, Leather, OKX); legacy fallback covers sats-connect\n * (Xverse), `window.unisat`, OKX legacy, and `window.btc`. The\n * fallback defers to Wallet Standard via `hasAnyPrimaryAdapter`.\n */\nconst bitcoinDiscoverer: PlatformDiscoverer = {\n fallback: {\n subscribe: (onAdapter, opts) =>\n discoverInjectedBitcoinAdapter(onAdapter, {\n hasAnyWalletStandardAdapter: opts.hasAnyPrimaryAdapter,\n }),\n },\n platform: \"bitcoin\",\n subscribe: discoverBitcoinAdapters,\n};\n\nexport { bitcoinDiscoverer };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["kitSlugify"],"sources":["../src/capabilities.ts","../src/wallet-standard-adapter.ts","../src/wallet-standard.ts","../src/chains.ts","../src/injected/icon.ts","../src/injected/sats-connect.ts","../src/injected/unisat.ts","../src/injected/index.ts","../src/discoverer.ts"],"sourcesContent":["import type { WalletCapabilities } from \"@usebutr/core\";\n\ntype BitcoinCapabilityInput = {\n chainCount: number;\n features: {\n events: boolean;\n sendTransfer: boolean;\n signMessage: boolean;\n signPsbt: boolean;\n };\n};\n\n/**\n * Bitcoin capability mapping.\n *\n * - `sendTransaction = bitcoin:sendTransfer present`. The wallet handles\n * UTXO selection, fee estimation, signing, and broadcast.\n * - `signTransaction = bitcoin:signPsbt present`. Sign-only PSBT path\n * for consumers that build their own UTXO-shaped transactions with\n * `bitcoinjs-lib` and broadcast through their own provider.\n * - `signMessage = bitcoin:signMessage present`.\n * - `signIn = false`. No Sign-In-With-Bitcoin standard yet (BIP-322 is\n * message-signing oriented, not auth).\n * - `subscribe = events present`. Most Bitcoin wallets don't emit\n * change events portably; capabilities admits the truth.\n * - `switchChain = false`. No portable per-call switch RPC across\n * Bitcoin wallets — Xverse/Unisat/Phantom each pick their own network.\n */\nconst resolveBitcoinCapabilities = (input: BitcoinCapabilityInput): WalletCapabilities => ({\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: false,\n sendTransaction: input.features.sendTransfer,\n signIn: false,\n signMessage: input.features.signMessage,\n signTransaction: input.features.signPsbt,\n subscribe: input.features.events,\n switchAccount: false,\n switchChain: input.chainCount > 1,\n});\n\nexport type { BitcoinCapabilityInput };\nexport { resolveBitcoinCapabilities };\n","import type { Account, ChainBase, ConnectorEvent, WalletAdapter } from \"@usebutr/core\";\nimport { logWarn, sanitizeIcon } from \"@usebutr/core\";\nimport {\n buildAccount,\n getFeature,\n pickAccountByAddress,\n pickFirstAddress,\n slugify as kitSlugify,\n} from \"@usebutr/wallet-standard-shared\";\nimport type {\n StandardConnectFeature,\n StandardDisconnectFeature,\n StandardEventsFeature,\n WalletStandardWallet,\n} from \"@usebutr/wallet-standard-shared\";\n\nimport { resolveBitcoinCapabilities } from \"./capabilities\";\nimport type {\n BitcoinSendTransferFeature,\n BitcoinSignMessageFeature,\n BitcoinSignPsbtFeature,\n} from \"./wallet-standard-types\";\n\nconst BITCOIN_PREFIX = \"bip122:\";\nconst BITCOIN_DECIMALS = 8;\nconst BITCOIN_MAINNET_ID = \"bip122:000000000019d6689c085ae165831e93\";\n\nconst slugify = (name: string): string => kitSlugify(\"btc\", name);\n\nconst pickBitcoinChain = (wallet: WalletStandardWallet): string | null => {\n const mainnet = wallet.chains.find((c) => c === BITCOIN_MAINNET_ID);\n if (mainnet) {\n return mainnet;\n }\n return wallet.chains.find((c) => c.startsWith(BITCOIN_PREFIX)) ?? null;\n};\n\nconst buildBitcoinChain = (chainId: string, walletName: string): ChainBase => ({\n id: chainId,\n // Same posture as EVM/SVM/Sui: butr ships no chain-id → name table.\n name: walletName,\n namespace: \"bip122\",\n reference: chainId.slice(BITCOIN_PREFIX.length),\n});\n\nconst buildBitcoinAccount = (address: string, chain: ChainBase): Account =>\n buildAccount(address, chain);\n\n/**\n * Adapt a Bitcoin Wallet Standard `Wallet` into a butr `WalletAdapter`.\n *\n * Returns `null` if the wallet doesn't advertise any `bip122:` chain or\n * doesn't expose `standard:connect`. Same posture as the SVM/Sui\n * adapters: gate features on what each wallet advertises, return\n * placeholders for RPC reads, forward `subscribe` through\n * `standard:events`.\n *\n * **Known limitations**\n *\n * - `getBalance` returns `{ value: 0n, symbol: \"BTC\" }`. Bitcoin\n * balance lookups require an Esplora/Electrum/RPC client outside\n * butr's scope.\n * - `getTransactionReceipt` returns `\"Pending\"` for the same reason.\n * - `sendTx` expects the consumer to pass `{ amount: bigint, recipient: string }`\n * via butr's `unknown` tx parameter — the simplest mental model that\n * maps onto `bitcoin:sendTransfer`. PSBT-shaped flows go through\n * `signTransaction`.\n * - `signTransaction` expects a `Uint8Array` PSBT (raw bytes) — the\n * same shape `bitcoin:signPsbt` accepts. Consumers building with\n * `bitcoinjs-lib` get bytes via `psbt.toBuffer()`.\n * - `switchChain` is local-state-only; the capability flag is `false`\n * when only one chain is advertised. Wallets that ship a real switch\n * primitive (none today, portably) would need their own adapter.\n */\nconst buildBitcoinAdapter = (\n wallet: WalletStandardWallet,\n /** Optional. Called with a function that pushes a synthetic\n * `disconnected` event to all current subscribers. The discovery\n * layer invokes it on Wallet Standard `unregister`. */\n registerDisconnector?: (emit: () => void) => void,\n): WalletAdapter | null => {\n const bitcoinChainId = pickBitcoinChain(wallet);\n if (!bitcoinChainId) {\n return null;\n }\n const connect = getFeature<StandardConnectFeature>(wallet, \"standard:connect\");\n if (!connect) {\n return null;\n }\n\n const disconnect = getFeature<StandardDisconnectFeature>(wallet, \"standard:disconnect\");\n const events = getFeature<StandardEventsFeature>(wallet, \"standard:events\");\n const signMessage = getFeature<BitcoinSignMessageFeature>(wallet, \"bitcoin:signMessage\");\n const signPsbt = getFeature<BitcoinSignPsbtFeature>(wallet, \"bitcoin:signPsbt\");\n const sendTransfer = getFeature<BitcoinSendTransferFeature>(wallet, \"bitcoin:sendTransfer\");\n\n let currentChainId = bitcoinChainId;\n const currentChain = (): ChainBase => buildBitcoinChain(currentChainId, wallet.name);\n\n const listeners = new Set<(event: ConnectorEvent) => void>();\n const notifyAccountChanged = () => {\n if (wallet.accounts.length === 0) {\n return;\n }\n const chain = currentChain();\n const built = wallet.accounts.map((a) => buildBitcoinAccount(a.address, chain));\n const first = built[0];\n if (!first) {\n return;\n }\n for (const listener of listeners) {\n listener({ account: first, accounts: built, type: \"accountChanged\" });\n }\n };\n\n registerDisconnector?.(() => {\n for (const listener of listeners) {\n listener({ type: \"disconnected\" });\n }\n });\n\n return {\n capabilities: resolveBitcoinCapabilities({\n chainCount: wallet.chains.filter((c) => c.startsWith(BITCOIN_PREFIX)).length,\n features: {\n events: Boolean(events),\n sendTransfer: Boolean(sendTransfer),\n signMessage: Boolean(signMessage),\n signPsbt: Boolean(signPsbt),\n },\n }),\n chainPlatform: \"bitcoin\",\n\n async connect(opts) {\n await connect.connect(opts?.silent ? { silent: true } : undefined);\n },\n\n async disconnect() {\n if (disconnect) {\n try {\n await disconnect.disconnect();\n } catch (error) {\n logWarn(\"[butr] Bitcoin Wallet Standard disconnect threw:\", error);\n }\n }\n },\n\n getAccount() {\n const address = pickFirstAddress(wallet.accounts);\n if (!address) {\n return Promise.resolve(null);\n }\n return Promise.resolve(buildBitcoinAccount(address, currentChain()));\n },\n\n getAccounts() {\n const chain = currentChain();\n return Promise.resolve(wallet.accounts.map((a) => buildBitcoinAccount(a.address, chain)));\n },\n\n getBalance() {\n return Promise.resolve({\n decimals: BITCOIN_DECIMALS,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n });\n },\n\n getSigner() {\n // Consumers cast to whatever Bitcoin signing wrapper they use\n // (bitcoinjs-lib's Signer, scure-btc-signer's HDWallet, etc.) or\n // call butr's adapter directly for PSBT / send-transfer.\n return Promise.resolve(wallet);\n },\n\n getTransactionReceipt() {\n return Promise.resolve({ status: \"Pending\" as const });\n },\n\n icon: sanitizeIcon(wallet.icon),\n id: slugify(wallet.name),\n name: wallet.name,\n\n async requestAccounts() {\n await connect.connect();\n },\n\n async sendTx(tx, account) {\n if (!sendTransfer) {\n throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:sendTransfer`);\n }\n if (\n !tx ||\n typeof tx !== \"object\" ||\n typeof (tx as { amount?: unknown }).amount !== \"bigint\" ||\n typeof (tx as { recipient?: unknown }).recipient !== \"string\"\n ) {\n throw new TypeError(\n \"Bitcoin sendTx expects { amount: bigint, recipient: string } — pass the recipient address and an amount in satoshis\",\n );\n }\n const { amount, recipient } = tx as { amount: bigint; recipient: string };\n const wsAccount = account\n ? pickAccountByAddress(wallet.accounts, account.walletAddress)\n : (wallet.accounts[0] ?? null);\n if (!wsAccount) {\n throw new Error(\"No connected account\");\n }\n const output = await sendTransfer.sendTransfer({\n account: wsAccount,\n amount,\n chain: currentChainId,\n recipient,\n });\n return output.txid;\n },\n\n sendTxToChain(tx, _targetChainId, account, cb) {\n cb?.();\n return this.sendTx(tx, account);\n },\n\n async signMessage(msg, account) {\n if (!signMessage) {\n throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:signMessage`);\n }\n const wsAccount = account\n ? pickAccountByAddress(wallet.accounts, account.walletAddress)\n : (wallet.accounts[0] ?? null);\n if (!wsAccount) {\n throw new Error(\"No connected account\");\n }\n const output = await signMessage.signMessage({ account: wsAccount, message: msg });\n return { signature: output.signature, signedMessage: output.signedMessage };\n },\n\n ...(signPsbt\n ? {\n async signTransaction(tx, account) {\n const wsAccount = account\n ? pickAccountByAddress(wallet.accounts, account.walletAddress)\n : (wallet.accounts[0] ?? null);\n if (!wsAccount) {\n throw new Error(\"No connected account\");\n }\n if (!(tx instanceof Uint8Array)) {\n throw new TypeError(\n \"Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())\",\n );\n }\n const output = await signPsbt.signPsbt({\n account: wsAccount,\n chain: currentChainId,\n psbt: tx,\n });\n return output.signedPsbt;\n },\n }\n : {}),\n\n subscribe(listener) {\n listeners.add(listener);\n let unsubWallet: (() => void) | null = null;\n if (events) {\n const unsub = events.on(\"change\", (changes) => {\n if (changes.chains) {\n const next =\n changes.chains.find((c) => c === BITCOIN_MAINNET_ID) ??\n changes.chains.find((c) => c.startsWith(BITCOIN_PREFIX));\n if (next) {\n currentChainId = next;\n }\n }\n\n if (changes.accounts) {\n if (changes.accounts.length === 0) {\n listener({ type: \"disconnected\" });\n return;\n }\n const chain = currentChain();\n const built = changes.accounts.map((a) => buildBitcoinAccount(a.address, chain));\n const first = built[0];\n if (!first) {\n return;\n }\n listener({ account: first, accounts: built, type: \"accountChanged\" });\n return;\n }\n\n if (changes.chains) {\n notifyAccountChanged();\n }\n });\n unsubWallet = () => unsub();\n }\n return () => {\n listeners.delete(listener);\n unsubWallet?.();\n };\n },\n\n switchChain(chain) {\n if (chain.namespace !== \"bip122\") {\n throw new Error(\n `Bitcoin adapter received non-Bitcoin chain \"${chain.id}\". Pass a chain with namespace \"bip122\".`,\n );\n }\n if (!wallet.chains.includes(chain.id)) {\n throw new Error(\n `Wallet ${wallet.name} does not advertise chain \"${chain.id}\". Available: ${wallet.chains.join(\", \")}`,\n );\n }\n currentChainId = chain.id;\n notifyAccountChanged();\n return Promise.resolve();\n },\n };\n};\n\nexport { buildBitcoinAdapter, slugify };\n","import type { WalletAdapter } from \"@usebutr/core\";\nimport { discoverWalletStandard } from \"@usebutr/wallet-standard-shared\";\n\nimport { buildBitcoinAdapter } from \"./wallet-standard-adapter\";\n\n/**\n * Subscribe to Bitcoin Wallet Standard announcements.\n *\n * Phantom (Bitcoin), Magic Eden, OKX Wallet (Bitcoin), and Leather\n * advertise `bitcoin:*` features over the same `getWallets()` bus that\n * SVM and Sui consume. `buildBitcoinAdapter` returns `null` for wallets\n * that don't advertise any `bip122:` chain, so multi-chain wallets\n * (Phantom: EVM + SVM + Sui + Bitcoin) produce one adapter per platform.\n *\n * Requires the **optional peer dependency** `@wallet-standard/app`.\n *\n * The discovery loop (dynamic import, dedupe, register / unregister\n * bridge) lives in `@usebutr/wallet-standard-shared`.\n */\nconst discoverBitcoinAdapters = (onAdapter: (adapter: WalletAdapter) => void): (() => void) =>\n discoverWalletStandard(onAdapter, (wallet, registerDisconnector) =>\n buildBitcoinAdapter(wallet, registerDisconnector),\n );\n\nexport { discoverBitcoinAdapters };\n","import type { ChainBase } from \"@usebutr/core\";\n\n/**\n * CAIP-2 Bitcoin chain references use the first 8 bytes (big-endian)\n * of each network's genesis block hash. These string ids are what\n * Bitcoin Wallet Standard wallets (Phantom, Magic Eden, OKX) advertise\n * in `wallet.chains`; the adapter's `switchChain` rejects anything else.\n *\n * - Mainnet: `bip122:000000000019d6689c085ae165831e93`\n * - Testnet: `bip122:000000000933ea01ad0ee984209779ba`\n * - Signet: `bip122:00000008819873e925422c1ff0f99f7c`\n *\n * Bitcoin has no per-call \"switch chain\" RPC across the major wallets,\n * so butr's adapter treats chain as a wallet-side configuration —\n * `switchChain` updates local state to influence subsequent calls (same\n * posture as SVM). Bitcoin's `switchChain` capability is `false` by\n * default; consumers building on top can opt in if their wallet exposes\n * a switch primitive.\n */\nconst BITCOIN_CHAINS = {\n mainnet: {\n id: \"bip122:000000000019d6689c085ae165831e93\",\n name: \"Bitcoin\",\n namespace: \"bip122\",\n reference: \"000000000019d6689c085ae165831e93\",\n },\n signet: {\n id: \"bip122:00000008819873e925422c1ff0f99f7c\",\n name: \"Bitcoin Signet\",\n namespace: \"bip122\",\n reference: \"00000008819873e925422c1ff0f99f7c\",\n },\n testnet: {\n id: \"bip122:000000000933ea01ad0ee984209779ba\",\n name: \"Bitcoin Testnet\",\n namespace: \"bip122\",\n reference: \"000000000933ea01ad0ee984209779ba\",\n },\n} as const satisfies Record<string, ChainBase>;\n\nconst BITCOIN_CHAINS_LIST: ReadonlyArray<ChainBase> = Object.values(BITCOIN_CHAINS);\n\nexport { BITCOIN_CHAINS, BITCOIN_CHAINS_LIST };\n","/**\n * Generic Bitcoin wallet icon — same purse SVG style as the EVM\n * package, recoloured. Inline so the picker doesn't flash.\n *\n * Lives in its own file because both injected adapters (UniSat-shape\n * and sats-connect) need the same fallback when the wallet doesn't\n * advertise its own icon, and there's no other \"shared\" thing they\n * both want — a one-line module beats a grab-bag.\n */\nconst GENERIC_BITCOIN_ICON =\n \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2Y3OTMxYSIgc3Ryb2tlPSJub25lIj48Y2lyY2xlIGN4PSIxMiIgY3k9IjEyIiByPSIxMCIvPjx0ZXh0IHg9IjEyIiB5PSIxNyIgZm9udC1mYW1pbHk9InNlcmlmIiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iYm9sZCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+QjwvdGV4dD48L3N2Zz4=\";\n\nexport { GENERIC_BITCOIN_ICON };\n","import type { ChainBase, WalletAdapter, WalletCapabilities } from \"@usebutr/core\";\nimport { base64ToBytes, bytesToBase64 } from \"@usebutr/core\";\nimport { buildAccount } from \"@usebutr/wallet-standard-shared\";\n\nimport { BITCOIN_CHAINS } from \"../chains\";\n\nimport { GENERIC_BITCOIN_ICON } from \"./icon\";\n\n/** sats-connect (Xverse) shape — a JSON-RPC-ish `request(method, params)`. */\ntype SatsConnectProvider = {\n request: (\n method: string,\n params?: Record<string, unknown>,\n ) => Promise<{ error?: { message: string }; result?: unknown }>;\n};\n\nconst CAPS_SATS_CONNECT: WalletCapabilities = {\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: true,\n sendTransaction: true,\n signIn: false,\n signMessage: true,\n signTransaction: true,\n subscribe: false,\n switchAccount: false,\n switchChain: false,\n};\n\n/**\n * Wrap an Xverse-style `BitcoinProvider` (sats-connect) into a butr\n * `WalletAdapter`. sats-connect routes everything through a single\n * `request(method, params)` RPC; we shim each butr capability onto the\n * corresponding sats-connect method.\n *\n * Tested against Xverse's `getAccounts`, `signMessage`, `signPsbt`,\n * `sendTransfer` methods.\n */\nconst buildSatsConnectAdapter = (\n id: string,\n name: string,\n provider: SatsConnectProvider,\n): WalletAdapter => {\n let chain: ChainBase = BITCOIN_CHAINS.mainnet;\n let cachedAccounts: ReadonlyArray<string> = [];\n\n const callRequest = async <T>(method: string, params?: Record<string, unknown>): Promise<T> => {\n const response = await provider.request(method, params);\n if (response.error) {\n throw new Error(`[butr/bitcoin] sats-connect ${method} failed: ${response.error.message}`);\n }\n return response.result as T;\n };\n\n const loadAccounts = async (): Promise<ReadonlyArray<string>> => {\n const result = await callRequest<{\n addresses?: ReadonlyArray<{ address: string; purpose?: string }>;\n }>(\"getAccounts\", {\n message: \"Connect to butr\",\n purposes: [\"payment\", \"ordinals\"],\n });\n if (!result?.addresses) {\n return [];\n }\n const addresses = result.addresses.map((a) => a.address);\n cachedAccounts = addresses;\n return addresses;\n };\n\n return {\n capabilities: CAPS_SATS_CONNECT,\n chainPlatform: \"bitcoin\",\n\n async connect() {\n await loadAccounts();\n },\n\n disconnect() {\n cachedAccounts = [];\n return Promise.resolve();\n },\n\n async getAccount() {\n const first = cachedAccounts[0];\n if (first) {\n return buildAccount(first, chain);\n }\n const accounts = await loadAccounts();\n const firstFresh = accounts[0];\n return firstFresh ? buildAccount(firstFresh, chain) : null;\n },\n\n async getAccounts() {\n const accounts = cachedAccounts.length > 0 ? cachedAccounts : await loadAccounts();\n return accounts.map((a) => buildAccount(a, chain));\n },\n\n getBalance() {\n return Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n });\n },\n\n getSigner() {\n return Promise.resolve(provider);\n },\n\n getTransactionReceipt() {\n return Promise.resolve({ status: \"Pending\" as const });\n },\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n async requestAccounts() {\n await loadAccounts();\n },\n\n async sendTx(tx) {\n if (\n !tx ||\n typeof tx !== \"object\" ||\n typeof (tx as { recipient?: unknown }).recipient !== \"string\" ||\n typeof (tx as { amount?: unknown }).amount !== \"bigint\"\n ) {\n throw new TypeError(\n \"Bitcoin sendTx expects { amount: bigint, recipient: string } — amount in satoshis\",\n );\n }\n const { amount, recipient } = tx as { amount: bigint; recipient: string };\n const result = await callRequest<{ txid: string }>(\"sendTransfer\", {\n recipients: [{ address: recipient, amount: amount.toString() }],\n });\n return result.txid;\n },\n\n sendTxToChain(tx, _targetChainId, _account, cb) {\n cb?.();\n return this.sendTx(tx);\n },\n\n async signMessage(msg) {\n const address = cachedAccounts[0];\n if (!address) {\n throw new Error(\"No connected account\");\n }\n const result = await callRequest<{ messageHash?: string; signature: string }>(\"signMessage\", {\n address,\n message: new TextDecoder().decode(msg),\n });\n return { signature: base64ToBytes(result.signature), signedMessage: msg };\n },\n\n async signTransaction(tx) {\n if (!(tx instanceof Uint8Array)) {\n throw new TypeError(\n \"Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())\",\n );\n }\n // sats-connect's signPsbt takes a base64 PSBT; encode our bytes\n // and decode the response back to bytes.\n const result = await callRequest<{ psbt: string }>(\"signPsbt\", {\n psbt: bytesToBase64(tx),\n });\n return base64ToBytes(result.psbt);\n },\n\n switchChain(target) {\n if (target.namespace !== \"bip122\") {\n throw new Error(\n `Bitcoin adapter received non-Bitcoin chain \"${target.id}\". Pass a chain with namespace \"bip122\".`,\n );\n }\n chain = target;\n return Promise.resolve();\n },\n };\n};\n\nexport type { SatsConnectProvider };\nexport { buildSatsConnectAdapter };\n","import type { ChainBase, ConnectorEvent, WalletAdapter, WalletCapabilities } from \"@usebutr/core\";\nimport { base64ToBytes, bytesToHex, hexToBytes } from \"@usebutr/core\";\nimport { buildAccount } from \"@usebutr/wallet-standard-shared\";\n\nimport { BITCOIN_CHAINS } from \"../chains\";\n\nimport { GENERIC_BITCOIN_ICON } from \"./icon\";\n\n/** UniSat-style provider: a single object on `window.unisat` with the\n * same four methods every UniSat-derivative wallet exposes (UniSat\n * itself, OKX Wallet's Bitcoin path at `window.okxwallet.bitcoin`). */\ntype UnisatProvider = {\n getAccounts: () => Promise<ReadonlyArray<string>>;\n getNetwork?: () => Promise<\"livenet\" | \"mainnet\" | \"testnet\" | \"signet\">;\n on?: (\n event: \"accountsChanged\" | \"networkChanged\",\n listener: (...args: Array<unknown>) => void,\n ) => void;\n pushPsbt?: (psbtHex: string) => Promise<string>;\n removeListener?: (\n event: \"accountsChanged\" | \"networkChanged\",\n listener: (...args: Array<unknown>) => void,\n ) => void;\n requestAccounts: () => Promise<ReadonlyArray<string>>;\n sendBitcoin?: (recipient: string, amount: number) => Promise<string>;\n signMessage: (message: string, type?: \"ecdsa\" | \"bip322-simple\") => Promise<string>;\n signPsbt: (psbtHex: string, options?: Record<string, unknown>) => Promise<string>;\n};\n\nconst CAPS_UNISAT: WalletCapabilities = {\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: true,\n sendTransaction: true,\n signIn: false,\n signMessage: true,\n signTransaction: true,\n subscribe: true,\n switchAccount: false,\n switchChain: false,\n};\n\n/**\n * Wrap a UniSat-style provider (`window.unisat`, `window.okxwallet.bitcoin`,\n * `window.btc`) into a butr `WalletAdapter`.\n *\n * The UniSat shape is consistent enough that one adapter handles every\n * derivative. Differences (network names, `sendBitcoin` presence) are\n * gated by feature detection per call.\n */\nconst buildUnisatAdapter = (id: string, name: string, provider: UnisatProvider): WalletAdapter => {\n let chain: ChainBase = BITCOIN_CHAINS.mainnet;\n const listenersSet = new Set<(event: ConnectorEvent) => void>();\n\n const refreshChain = async () => {\n if (typeof provider.getNetwork !== \"function\") {\n return;\n }\n try {\n const network = await provider.getNetwork();\n if (network === \"testnet\") {\n chain = BITCOIN_CHAINS.testnet;\n } else if (network === \"signet\") {\n chain = BITCOIN_CHAINS.signet;\n } else {\n chain = BITCOIN_CHAINS.mainnet;\n }\n } catch {\n // Network probe failed — keep the current chain. The next call\n // will retry through whichever path next invokes refreshChain.\n }\n };\n\n return {\n capabilities: CAPS_UNISAT,\n chainPlatform: \"bitcoin\",\n\n async connect(opts) {\n if (opts?.silent) {\n const accounts = await provider.getAccounts();\n if (accounts.length === 0) {\n throw new Error(\"No authorized accounts for silent reconnect\");\n }\n await refreshChain();\n return;\n }\n await provider.requestAccounts();\n await refreshChain();\n },\n\n disconnect() {\n // No portable disconnect across UniSat-shaped wallets. butr's\n // reducer marks the wallet disconnected on its side regardless.\n return Promise.resolve();\n },\n\n async getAccount() {\n const accounts = await provider.getAccounts();\n const first = accounts[0];\n if (!first) {\n return null;\n }\n await refreshChain();\n return buildAccount(first, chain);\n },\n\n async getAccounts() {\n const accounts = await provider.getAccounts();\n if (accounts.length === 0) {\n return [];\n }\n await refreshChain();\n return accounts.map((a) => buildAccount(a, chain));\n },\n\n getBalance() {\n return Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n });\n },\n\n getSigner() {\n return Promise.resolve(provider);\n },\n\n getTransactionReceipt() {\n return Promise.resolve({ status: \"Pending\" as const });\n },\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n async requestAccounts() {\n await provider.requestAccounts();\n await refreshChain();\n },\n\n sendTx(tx) {\n if (typeof provider.sendBitcoin !== \"function\") {\n throw new TypeError(`Wallet ${name} does not expose sendBitcoin`);\n }\n if (\n !tx ||\n typeof tx !== \"object\" ||\n typeof (tx as { recipient?: unknown }).recipient !== \"string\" ||\n typeof (tx as { amount?: unknown }).amount !== \"bigint\"\n ) {\n throw new TypeError(\n \"Bitcoin sendTx expects { amount: bigint, recipient: string } — amount in satoshis\",\n );\n }\n const { amount, recipient } = tx as { amount: bigint; recipient: string };\n // UniSat's sendBitcoin takes a JS number for satoshis. Values\n // above 2^53 aren't representable; that's 90+ million BTC, which\n // would never appear in practice.\n const sats = Number(amount);\n return provider.sendBitcoin(recipient, sats);\n },\n\n sendTxToChain(tx, _targetChainIdDecimal, _account, cb) {\n cb?.();\n return this.sendTx(tx);\n },\n\n async signMessage(msg) {\n // UniSat takes a UTF-8 message and returns a base64 signature.\n // We return the raw signature bytes (decoded from base64) and the\n // bytes the wallet signed (pass-through of the input). UniSat\n // doesn't expose a \"pre-image\" so the input itself is the signed\n // message from butr's perspective.\n const text = new TextDecoder().decode(msg);\n const signatureB64 = await provider.signMessage(text);\n return { signature: base64ToBytes(signatureB64), signedMessage: msg };\n },\n\n async signTransaction(tx) {\n if (!(tx instanceof Uint8Array)) {\n throw new TypeError(\n \"Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())\",\n );\n }\n const signedHex = await provider.signPsbt(bytesToHex(tx));\n return hexToBytes(signedHex);\n },\n\n subscribe(listener) {\n listenersSet.add(listener);\n const onAccountsChanged = (...args: ReadonlyArray<unknown>) => {\n const accounts = (args[0] as ReadonlyArray<string> | undefined) ?? [];\n if (accounts.length === 0) {\n listener({ type: \"disconnected\" });\n return;\n }\n const built = accounts.map((a) => buildAccount(a, chain));\n const first = built[0];\n if (!first) {\n return;\n }\n listener({ account: first, accounts: built, type: \"accountChanged\" });\n };\n const onNetworkChanged = () => {\n void refreshChain();\n };\n provider.on?.(\"accountsChanged\", onAccountsChanged);\n provider.on?.(\"networkChanged\", onNetworkChanged);\n return () => {\n provider.removeListener?.(\"accountsChanged\", onAccountsChanged);\n provider.removeListener?.(\"networkChanged\", onNetworkChanged);\n listenersSet.delete(listener);\n };\n },\n\n switchChain(target) {\n if (target.namespace !== \"bip122\") {\n throw new Error(\n `Bitcoin adapter received non-Bitcoin chain \"${target.id}\". Pass a chain with namespace \"bip122\".`,\n );\n }\n // UniSat-shaped wallets pick their network via the user's\n // extension UI; we update local state so consumers see it, but\n // the wallet itself doesn't switch.\n chain = target;\n void refreshChain();\n return Promise.resolve();\n },\n };\n};\n\nexport type { UnisatProvider };\nexport { buildUnisatAdapter };\n","import type { WalletAdapter } from \"@usebutr/core\";\n\nimport type { SatsConnectProvider } from \"./sats-connect\";\nimport { buildSatsConnectAdapter } from \"./sats-connect\";\nimport type { UnisatProvider } from \"./unisat\";\nimport { buildUnisatAdapter } from \"./unisat\";\n\nconst DEFAULT_SETTLE_MS = 150;\n\ntype InjectedHost = {\n btc?: UnisatProvider;\n okxwallet?: { bitcoin?: UnisatProvider };\n unisat?: UnisatProvider;\n XverseProviders?: { BitcoinProvider?: SatsConnectProvider };\n};\n\ntype InjectedBitcoinDiscoveryOptions = {\n /** Suppresses emission when Wallet Standard discovery has already\n * registered a Bitcoin adapter for the same browser session. */\n hasAnyWalletStandardAdapter?: () => boolean;\n /** Settle deadline in ms before the fallback fires. Same default and\n * intent as the EVM injected fallback. */\n settleMs?: number;\n /** Override the global host (tests, iframes). */\n target?: InjectedHost | null;\n};\n\nconst readHost = (target: InjectedBitcoinDiscoveryOptions[\"target\"]): InjectedHost | null => {\n const globalWindow = typeof window === \"undefined\" ? null : (window as unknown as InjectedHost);\n return target === undefined ? globalWindow : target;\n};\n\nconst probeProviders = (host: InjectedHost): Array<WalletAdapter> => {\n const adapters: Array<WalletAdapter> = [];\n const seen = new Set<UnisatProvider | SatsConnectProvider>();\n\n if (host.unisat && !seen.has(host.unisat)) {\n seen.add(host.unisat);\n adapters.push(buildUnisatAdapter(\"injected:bitcoin:unisat\", \"Unisat\", host.unisat));\n }\n\n const okxBitcoin = host.okxwallet?.bitcoin;\n if (okxBitcoin && !seen.has(okxBitcoin)) {\n seen.add(okxBitcoin);\n adapters.push(buildUnisatAdapter(\"injected:bitcoin:okx\", \"OKX Wallet (Bitcoin)\", okxBitcoin));\n }\n\n const xverse = host.XverseProviders?.BitcoinProvider;\n if (xverse && !seen.has(xverse)) {\n seen.add(xverse);\n adapters.push(buildSatsConnectAdapter(\"injected:bitcoin:xverse\", \"Xverse\", xverse));\n }\n\n if (host.btc && !seen.has(host.btc)) {\n seen.add(host.btc);\n adapters.push(\n buildUnisatAdapter(\"injected:bitcoin:legacy\", \"Browser Bitcoin wallet\", host.btc),\n );\n }\n\n return adapters;\n};\n\n/**\n * Last-resort discovery path for Bitcoin wallets that DON'T announce via\n * Wallet Standard. Probes, in order: `window.unisat`,\n * `window.okxwallet.bitcoin`, `window.XverseProviders.BitcoinProvider`,\n * `window.btc`.\n *\n * Wallet Standard wallets (Phantom, Magic Eden, Leather, modern OKX\n * builds) are already handled by `discoverBitcoinAdapters`. This\n * fallback waits `settleMs` (default 150ms), consults\n * `hasAnyWalletStandardAdapter` if provided, and emits adapters for\n * any injected providers that weren't already covered.\n *\n * Each emitted adapter has a stable id prefix (`injected:bitcoin:*`)\n * so consumers can distinguish them in the picker UI.\n */\nconst discoverInjectedBitcoinAdapter = (\n onAdapter: (adapter: WalletAdapter) => void,\n options: InjectedBitcoinDiscoveryOptions = {},\n): (() => void) => {\n const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;\n let cancelled = false;\n const timer = setTimeout(() => {\n if (cancelled) {\n return;\n }\n if (options.hasAnyWalletStandardAdapter?.()) {\n return;\n }\n const host = readHost(options.target);\n if (!host) {\n return;\n }\n const adapters = probeProviders(host);\n for (const adapter of adapters) {\n onAdapter(adapter);\n }\n }, settleMs);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n};\n\nexport type { InjectedBitcoinDiscoveryOptions };\nexport { GENERIC_BITCOIN_ICON } from \"./icon\";\nexport { discoverInjectedBitcoinAdapter };\n","import type { PlatformDiscoverer } from \"@usebutr/core\";\n\nimport { discoverInjectedBitcoinAdapter } from \"./injected\";\nimport { discoverBitcoinAdapters } from \"./wallet-standard\";\n\n/**\n * Bitcoin's `PlatformDiscoverer`: Wallet Standard primary (Phantom,\n * Magic Eden, Leather, OKX); legacy fallback covers sats-connect\n * (Xverse), `window.unisat`, OKX legacy, and `window.btc`. The\n * fallback defers to Wallet Standard via `hasAnyPrimaryAdapter`.\n */\nconst bitcoinDiscoverer: PlatformDiscoverer = {\n fallback: {\n subscribe: (onAdapter, opts) =>\n discoverInjectedBitcoinAdapter(onAdapter, {\n hasAnyWalletStandardAdapter: opts.hasAnyPrimaryAdapter,\n }),\n },\n platform: \"bitcoin\",\n subscribe: discoverBitcoinAdapters,\n};\n\nexport { bitcoinDiscoverer };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usebutr/bitcoin",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Wallet Standard + injected (sats-connect / Unisat / OKX) wallet discovery and adapters for butr (Bitcoin).",
5
5
  "license": "MIT",
6
6
  "author": "Pedro Filho <pedro@filho.me>",
@@ -25,13 +25,13 @@
25
25
  "access": "public"
26
26
  },
27
27
  "dependencies": {
28
- "@usebutr/core": "0.3.0",
29
- "@usebutr/wallet-standard-shared": "0.2.3"
28
+ "@usebutr/core": "0.4.1",
29
+ "@usebutr/wallet-standard-shared": "0.2.5"
30
30
  },
31
31
  "devDependencies": {
32
- "@wallet-standard/app": "^1.1.0",
32
+ "@wallet-standard/app": "^1.1.1",
33
33
  "typescript": "^6.0.3",
34
- "vitest": "^4.1.8",
34
+ "vitest": "^4.1.9",
35
35
  "@repo/config-vitest": "0.0.0",
36
36
  "@repo/typescript-config": "0.0.0"
37
37
  },