@usebutr/bitcoin 0.2.6 → 1.0.0
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 +4 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -136
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ChainBase, PlatformDiscoverer, WalletAdapter, WalletCapabilities } from "@usebutr/core";
|
|
2
1
|
import { WalletStandardWallet, WalletStandardWalletAccount } from "@usebutr/wallet-standard-shared";
|
|
2
|
+
import { ChainBase, PlatformDiscoverer, WalletAdapter, WalletCapabilities } from "@usebutr/core";
|
|
3
3
|
//#region src/wallet-standard-types.d.ts
|
|
4
4
|
type BitcoinSignMessageInput = {
|
|
5
5
|
account: WalletStandardWalletAccount;
|
|
@@ -45,7 +45,6 @@ type BitcoinSendTransferFeature = {
|
|
|
45
45
|
};
|
|
46
46
|
//#endregion
|
|
47
47
|
//#region src/wallet-standard-adapter.d.ts
|
|
48
|
-
declare const slugify: (name: string) => string;
|
|
49
48
|
/**
|
|
50
49
|
* Adapt a Bitcoin Wallet Standard `Wallet` into a butr `WalletAdapter`.
|
|
51
50
|
*
|
|
@@ -77,8 +76,6 @@ declare const buildBitcoinAdapter: (wallet: WalletStandardWallet,
|
|
|
77
76
|
* `disconnected` event to all current subscribers. The discovery
|
|
78
77
|
* layer invokes it on Wallet Standard `unregister`. */
|
|
79
78
|
registerDisconnector?: (emit: () => void) => void) => WalletAdapter | null;
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region src/wallet-standard.d.ts
|
|
82
79
|
/**
|
|
83
80
|
* Subscribe to Bitcoin Wallet Standard announcements.
|
|
84
81
|
*
|
|
@@ -146,7 +143,8 @@ type BitcoinCapabilityInput = {
|
|
|
146
143
|
};
|
|
147
144
|
};
|
|
148
145
|
/**
|
|
149
|
-
* Bitcoin capability mapping.
|
|
146
|
+
* Bitcoin feature → butr capability mapping. The flags that hold for every
|
|
147
|
+
* namespace are documented on `buildWalletCapabilities`.
|
|
150
148
|
*
|
|
151
149
|
* - `sendTransaction = bitcoin:sendTransfer present`. The wallet handles
|
|
152
150
|
* UTXO selection, fee estimation, signing, and broadcast.
|
|
@@ -158,10 +156,6 @@ type BitcoinCapabilityInput = {
|
|
|
158
156
|
* message-signing oriented, not auth).
|
|
159
157
|
* - `subscribe = events present`. Most Bitcoin wallets don't emit
|
|
160
158
|
* change events portably; capabilities admits the truth.
|
|
161
|
-
* - `switchChain = chainCount > 1`. No portable switch RPC across
|
|
162
|
-
* Bitcoin wallets (Xverse/Unisat/Phantom each pick their own
|
|
163
|
-
* network), so the switch is local-state-only and advertised only
|
|
164
|
-
* when the wallet exposes more than one chain to switch between.
|
|
165
159
|
*/
|
|
166
160
|
declare const resolveBitcoinCapabilities: (input: BitcoinCapabilityInput) => WalletCapabilities;
|
|
167
161
|
//#endregion
|
|
@@ -287,5 +281,5 @@ declare module "@usebutr/core" {
|
|
|
287
281
|
}
|
|
288
282
|
}
|
|
289
283
|
//#endregion
|
|
290
|
-
export { BITCOIN_CHAINS, BITCOIN_CHAINS_LIST, type BitcoinCapabilityInput, type BitcoinSendTransferFeature, type BitcoinSendTransferInput, type BitcoinSendTransferOutput, type BitcoinSignMessageFeature, type BitcoinSignMessageInput, type BitcoinSignMessageOutput, type BitcoinSignPsbtFeature, type BitcoinSignPsbtInput, type BitcoinSignPsbtOutput, GENERIC_BITCOIN_ICON, type InjectedBitcoinDiscoveryOptions, bitcoinDiscoverer, buildBitcoinAdapter, discoverBitcoinAdapters, discoverInjectedBitcoinAdapter, resolveBitcoinCapabilities
|
|
284
|
+
export { BITCOIN_CHAINS, BITCOIN_CHAINS_LIST, type BitcoinCapabilityInput, type BitcoinSendTransferFeature, type BitcoinSendTransferInput, type BitcoinSendTransferOutput, type BitcoinSignMessageFeature, type BitcoinSignMessageInput, type BitcoinSignMessageOutput, type BitcoinSignPsbtFeature, type BitcoinSignPsbtInput, type BitcoinSignPsbtOutput, GENERIC_BITCOIN_ICON, type InjectedBitcoinDiscoveryOptions, bitcoinDiscoverer, buildBitcoinAdapter, discoverBitcoinAdapters, discoverInjectedBitcoinAdapter, resolveBitcoinCapabilities };
|
|
291
285
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/wallet-standard-types.ts","../src/wallet-standard-adapter.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/wallet-standard-types.ts","../src/wallet-standard-adapter.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;EACH,SAAS;EACT,SAAS;;KAGN;EACH,WAAW;EACX,eAAe;;KAGZ;EACH,cAAc,OAAO,4BAA4B,QAAQ;;KAGtD;EACH,SAAS;;EAET;;EAEA,MAAM;;;EAGN,aAAa;;KAGV;;;EAGH,YAAY;;KAGT;EACH,WAAW,OAAO,yBAAyB,QAAQ;;KAGhD;EACH,SAAS;EACT;EACA;EACA;;KAGG;;EAEH;;KAGG;EACH,eAAe,OAAO,6BAA6B,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cClBvD,sBACJ,QAAQ,sBAIR;;;;AAAA,wBAAwB,8BACvB;;;;;;;;;;;;;;;cAiIG,0BAA2B,YAAY,SAAS;;;;;;;;;;;;;;;;;;;;cClKhD;;;;;;;;;;;;;;;;;;;;cAqBA,qBAAqB,cAAc;;;KCrCpC;EACH;EACA;IACE;IACA;IACA;IACA;;;;;;;;;;;;;;;;;;cAmBE,6BAA8B,OAAO,2BAAyB;;;;KCnB/D;EACH,UACE,gBACA,SAAS,4BACN;IAAU;MAAU;;IAAmB;;;;;;;;KCFzC;EACH,mBAAmB,QAAQ;EAC3B,mBAAmB;EACnB,MACE,6CACA,cAAc,MAAM;EAEtB,YAAY,oBAAoB;EAChC,kBACE,6CACA,cAAc,MAAM;EAEtB,uBAAuB,QAAQ;EAC/B,eAAe,mBAAmB,mBAAmB;EACrD,cAAc,iBAAiB,qCAAqC;EACpE,WAAW,iBAAiB,UAAU,4BAA4B;;;;;;;;;;;;;cCjB9D;;;KCAD;EACH,MAAM;EACN;IAAc,UAAU;;EACxB,SAAS;EACT;IAAoB,kBAAkB;;;KAGnC;;;EAGH;;;EAGA;;EAEA,SAAS;;;;;;;;;;;;;;;;;cA+DL,iCACJ,YAAY,SAAS,wBACrB,UAAS;;;;;;;;;cC9EL,mBAAmB;;;;;;;;;;;;;;;;;;KCMpB;EACH,mBAAmB,QAAQ;EAC3B,uBAAuB,QAAQ;EAC/B,cAAc,iBAAiB,kBAAkB;EACjD,WAAW,iBAAiB,UAAU,4BAA4B;;KAG/D;EACH,UACE,gBACA,SAAS,4BACN;IAAU;MAAU;;IAAmB;;;;YAKlC;IACR,SAAS,kBAAkB,aAAa"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { buildAccount, buildWalletCapabilities, createWalletStandardCore, discoverWalletStandard, getFeature, slugify } from "@usebutr/wallet-standard-shared";
|
|
2
|
+
import { base64ToBytes, bytesToBase64, bytesToHex, hexToBytes } from "@usebutr/core";
|
|
3
3
|
|
|
4
4
|
//#region src/capabilities.ts
|
|
5
5
|
/**
|
|
6
|
-
* Bitcoin capability mapping.
|
|
6
|
+
* Bitcoin feature → butr capability mapping. The flags that hold for every
|
|
7
|
+
* namespace are documented on `buildWalletCapabilities`.
|
|
7
8
|
*
|
|
8
9
|
* - `sendTransaction = bitcoin:sendTransfer present`. The wallet handles
|
|
9
10
|
* UTXO selection, fee estimation, signing, and broadcast.
|
|
@@ -15,22 +16,14 @@ import { buildAccount, discoverWalletStandard, getFeature, pickAccountByAddress,
|
|
|
15
16
|
* message-signing oriented, not auth).
|
|
16
17
|
* - `subscribe = events present`. Most Bitcoin wallets don't emit
|
|
17
18
|
* change events portably; capabilities admits the truth.
|
|
18
|
-
* - `switchChain = chainCount > 1`. No portable switch RPC across
|
|
19
|
-
* Bitcoin wallets (Xverse/Unisat/Phantom each pick their own
|
|
20
|
-
* network), so the switch is local-state-only and advertised only
|
|
21
|
-
* when the wallet exposes more than one chain to switch between.
|
|
22
19
|
*/
|
|
23
|
-
const resolveBitcoinCapabilities = (input) => ({
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
requestAccounts: false,
|
|
20
|
+
const resolveBitcoinCapabilities = (input) => buildWalletCapabilities({
|
|
21
|
+
chainCount: input.chainCount,
|
|
22
|
+
events: input.features.events,
|
|
27
23
|
sendTransaction: input.features.sendTransfer,
|
|
28
24
|
signIn: false,
|
|
29
25
|
signMessage: input.features.signMessage,
|
|
30
|
-
signTransaction: input.features.signPsbt
|
|
31
|
-
subscribe: input.features.events,
|
|
32
|
-
switchAccount: false,
|
|
33
|
-
switchChain: input.chainCount > 1
|
|
26
|
+
signTransaction: input.features.signPsbt
|
|
34
27
|
});
|
|
35
28
|
|
|
36
29
|
//#endregion
|
|
@@ -38,18 +31,6 @@ const resolveBitcoinCapabilities = (input) => ({
|
|
|
38
31
|
const BITCOIN_PREFIX = "bip122:";
|
|
39
32
|
const BITCOIN_DECIMALS = 8;
|
|
40
33
|
const BITCOIN_MAINNET_ID = "bip122:000000000019d6689c085ae165831e93";
|
|
41
|
-
const slugify = (name) => slugify$1("btc", name);
|
|
42
|
-
const pickBitcoinChain = (wallet) => {
|
|
43
|
-
const mainnet = wallet.chains.find((c) => c === BITCOIN_MAINNET_ID);
|
|
44
|
-
if (mainnet) return mainnet;
|
|
45
|
-
return wallet.chains.find((c) => c.startsWith(BITCOIN_PREFIX)) ?? null;
|
|
46
|
-
};
|
|
47
|
-
const buildBitcoinChain = (chainId, walletName) => ({
|
|
48
|
-
id: chainId,
|
|
49
|
-
name: walletName,
|
|
50
|
-
namespace: "bip122",
|
|
51
|
-
reference: chainId.slice(7)
|
|
52
|
-
});
|
|
53
34
|
/**
|
|
54
35
|
* Adapt a Bitcoin Wallet Standard `Wallet` into a butr `WalletAdapter`.
|
|
55
36
|
*
|
|
@@ -77,89 +58,53 @@ const buildBitcoinChain = (chainId, walletName) => ({
|
|
|
77
58
|
* primitive (none today, portably) would need their own adapter.
|
|
78
59
|
*/
|
|
79
60
|
const buildBitcoinAdapter = (wallet, registerDisconnector) => {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
61
|
+
const core = createWalletStandardCore({
|
|
62
|
+
chainPrefix: BITCOIN_PREFIX,
|
|
63
|
+
id: slugify("btc", wallet.name),
|
|
64
|
+
label: "Bitcoin",
|
|
65
|
+
namespace: "bip122",
|
|
66
|
+
platform: "Bitcoin",
|
|
67
|
+
preferredChainIds: [BITCOIN_MAINNET_ID],
|
|
68
|
+
registerDisconnector,
|
|
69
|
+
trackChainChanges: true,
|
|
70
|
+
wallet
|
|
71
|
+
});
|
|
72
|
+
if (core === null) return null;
|
|
86
73
|
const signMessage = getFeature(wallet, "bitcoin:signMessage");
|
|
87
74
|
const signPsbt = getFeature(wallet, "bitcoin:signPsbt");
|
|
88
75
|
const sendTransfer = getFeature(wallet, "bitcoin:sendTransfer");
|
|
89
|
-
let currentChainId = bitcoinChainId;
|
|
90
|
-
const currentChain = () => buildBitcoinChain(currentChainId, wallet.name);
|
|
91
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
92
|
-
const notifyAccountChanged = () => {
|
|
93
|
-
if (wallet.accounts.length === 0) return;
|
|
94
|
-
const chain = currentChain();
|
|
95
|
-
const built = wallet.accounts.map((a) => buildAccount(a.address, chain));
|
|
96
|
-
const first = built[0];
|
|
97
|
-
if (first === void 0) return;
|
|
98
|
-
for (const listener of listeners) listener({
|
|
99
|
-
account: first,
|
|
100
|
-
accounts: built,
|
|
101
|
-
type: "accountChanged"
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
|
-
registerDisconnector?.(() => {
|
|
105
|
-
for (const listener of listeners) listener({ type: "disconnected" });
|
|
106
|
-
});
|
|
107
76
|
const sendTransferTx = async (tx, account) => {
|
|
108
77
|
if (sendTransfer === void 0) throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:sendTransfer`);
|
|
109
78
|
if (typeof tx !== "object" || tx === null || !("amount" in tx) || typeof tx.amount !== "bigint" || !("recipient" in tx) || typeof tx.recipient !== "string") throw new TypeError("Bitcoin sendTx expects { amount: bigint, recipient: string }: pass the recipient address and an amount in satoshis");
|
|
110
79
|
const { amount, recipient } = tx;
|
|
111
|
-
const wsAccount = account ? pickAccountByAddress(wallet.accounts, account.walletAddress) : wallet.accounts[0];
|
|
112
|
-
if (wsAccount === void 0) throw new Error("No connected account");
|
|
113
80
|
return (await sendTransfer.sendTransfer({
|
|
114
|
-
account:
|
|
81
|
+
account: core.resolveAccount(account),
|
|
115
82
|
amount,
|
|
116
|
-
chain: currentChainId,
|
|
83
|
+
chain: core.currentChainId(),
|
|
117
84
|
recipient
|
|
118
85
|
})).txid;
|
|
119
86
|
};
|
|
120
87
|
return {
|
|
88
|
+
...core,
|
|
121
89
|
capabilities: resolveBitcoinCapabilities({
|
|
122
|
-
chainCount:
|
|
90
|
+
chainCount: core.chainCount,
|
|
123
91
|
features: {
|
|
124
|
-
events:
|
|
92
|
+
events: core.hasEvents,
|
|
125
93
|
sendTransfer: Boolean(sendTransfer),
|
|
126
94
|
signMessage: Boolean(signMessage),
|
|
127
95
|
signPsbt: Boolean(signPsbt)
|
|
128
96
|
}
|
|
129
97
|
}),
|
|
130
98
|
chainPlatform: "bitcoin",
|
|
131
|
-
async connect(opts) {
|
|
132
|
-
await connect.connect(opts?.silent === true ? { silent: true } : void 0);
|
|
133
|
-
},
|
|
134
|
-
async disconnect() {
|
|
135
|
-
if (disconnect !== void 0) try {
|
|
136
|
-
await disconnect.disconnect();
|
|
137
|
-
} catch (error) {
|
|
138
|
-
logWarn("[butr] Bitcoin Wallet Standard disconnect threw:", error);
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
getAccount: () => {
|
|
142
|
-
const address = pickFirstAddress(wallet.accounts);
|
|
143
|
-
if (address === null) return Promise.resolve(null);
|
|
144
|
-
return Promise.resolve(buildAccount(address, currentChain()));
|
|
145
|
-
},
|
|
146
|
-
getAccounts: () => {
|
|
147
|
-
const chain = currentChain();
|
|
148
|
-
return Promise.resolve(wallet.accounts.map((a) => buildAccount(a.address, chain)));
|
|
149
|
-
},
|
|
150
99
|
getBalance: () => Promise.resolve({
|
|
151
100
|
decimals: BITCOIN_DECIMALS,
|
|
152
101
|
formatted: "0",
|
|
153
102
|
symbol: "BTC",
|
|
154
103
|
value: 0n
|
|
155
104
|
}),
|
|
156
|
-
getSigner: () => Promise.resolve(wallet),
|
|
157
105
|
getTransactionReceipt: () => Promise.resolve({ status: "Pending" }),
|
|
158
|
-
icon: sanitizeIcon(wallet.icon),
|
|
159
|
-
id: slugify(wallet.name),
|
|
160
|
-
name: wallet.name,
|
|
161
106
|
async requestAccounts() {
|
|
162
|
-
await
|
|
107
|
+
await core.connect();
|
|
163
108
|
},
|
|
164
109
|
sendTx: (tx, account) => sendTransferTx(tx, account),
|
|
165
110
|
sendTxToChain: (tx, _targetChainId, account, cb) => {
|
|
@@ -168,10 +113,8 @@ const buildBitcoinAdapter = (wallet, registerDisconnector) => {
|
|
|
168
113
|
},
|
|
169
114
|
async signMessage(msg, account) {
|
|
170
115
|
if (signMessage === void 0) throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:signMessage`);
|
|
171
|
-
const wsAccount = account ? pickAccountByAddress(wallet.accounts, account.walletAddress) : wallet.accounts[0];
|
|
172
|
-
if (wsAccount === void 0) throw new Error("No connected account");
|
|
173
116
|
const output = await signMessage.signMessage({
|
|
174
|
-
account:
|
|
117
|
+
account: core.resolveAccount(account),
|
|
175
118
|
message: msg
|
|
176
119
|
});
|
|
177
120
|
return {
|
|
@@ -180,63 +123,16 @@ const buildBitcoinAdapter = (wallet, registerDisconnector) => {
|
|
|
180
123
|
};
|
|
181
124
|
},
|
|
182
125
|
...signPsbt === void 0 ? {} : { async signTransaction(tx, account) {
|
|
183
|
-
const wsAccount =
|
|
184
|
-
if (wsAccount === void 0) throw new Error("No connected account");
|
|
126
|
+
const wsAccount = core.resolveAccount(account);
|
|
185
127
|
if (!(tx instanceof Uint8Array)) throw new TypeError("Bitcoin signTransaction expects a PSBT as Uint8Array (e.g. psbt.toBuffer())");
|
|
186
128
|
return (await signPsbt.signPsbt({
|
|
187
129
|
account: wsAccount,
|
|
188
|
-
chain: currentChainId,
|
|
130
|
+
chain: core.currentChainId(),
|
|
189
131
|
psbt: tx
|
|
190
132
|
})).signedPsbt;
|
|
191
|
-
} }
|
|
192
|
-
subscribe(listener) {
|
|
193
|
-
listeners.add(listener);
|
|
194
|
-
let unsubWallet = null;
|
|
195
|
-
if (events !== void 0) {
|
|
196
|
-
const unsub = events.on("change", (changes) => {
|
|
197
|
-
if (changes.chains !== void 0) {
|
|
198
|
-
const next = changes.chains.find((c) => c === BITCOIN_MAINNET_ID) ?? changes.chains.find((c) => c.startsWith(BITCOIN_PREFIX));
|
|
199
|
-
if (next !== void 0) currentChainId = next;
|
|
200
|
-
}
|
|
201
|
-
if (changes.accounts !== void 0) {
|
|
202
|
-
if (changes.accounts.length === 0) {
|
|
203
|
-
listener({ type: "disconnected" });
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
const chain = currentChain();
|
|
207
|
-
const built = changes.accounts.map((a) => buildAccount(a.address, chain));
|
|
208
|
-
const first = built[0];
|
|
209
|
-
if (first === void 0) return;
|
|
210
|
-
listener({
|
|
211
|
-
account: first,
|
|
212
|
-
accounts: built,
|
|
213
|
-
type: "accountChanged"
|
|
214
|
-
});
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
if (changes.chains !== void 0) notifyAccountChanged();
|
|
218
|
-
});
|
|
219
|
-
unsubWallet = () => {
|
|
220
|
-
unsub();
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
return () => {
|
|
224
|
-
listeners.delete(listener);
|
|
225
|
-
unsubWallet?.();
|
|
226
|
-
};
|
|
227
|
-
},
|
|
228
|
-
switchChain: (chain) => {
|
|
229
|
-
if (chain.namespace !== "bip122") throw new Error(`Bitcoin adapter received non-Bitcoin chain "${chain.id}". Pass a chain with namespace "bip122".`);
|
|
230
|
-
if (!wallet.chains.includes(chain.id)) throw new Error(`Wallet ${wallet.name} does not advertise chain "${chain.id}". Available: ${wallet.chains.join(", ")}`);
|
|
231
|
-
currentChainId = chain.id;
|
|
232
|
-
notifyAccountChanged();
|
|
233
|
-
return Promise.resolve();
|
|
234
|
-
}
|
|
133
|
+
} }
|
|
235
134
|
};
|
|
236
135
|
};
|
|
237
|
-
|
|
238
|
-
//#endregion
|
|
239
|
-
//#region src/wallet-standard.ts
|
|
240
136
|
/**
|
|
241
137
|
* Subscribe to Bitcoin Wallet Standard announcements.
|
|
242
138
|
*
|
|
@@ -624,10 +520,9 @@ const discoverInjectedBitcoinAdapter = (onAdapter, options = {}) => {
|
|
|
624
520
|
*/
|
|
625
521
|
const bitcoinDiscoverer = {
|
|
626
522
|
fallback: { subscribe: (onAdapter, opts) => discoverInjectedBitcoinAdapter(onAdapter, { hasAnyWalletStandardAdapter: opts.hasAnyPrimaryAdapter }) },
|
|
627
|
-
platform: "bitcoin",
|
|
628
523
|
subscribe: discoverBitcoinAdapters
|
|
629
524
|
};
|
|
630
525
|
|
|
631
526
|
//#endregion
|
|
632
|
-
export { BITCOIN_CHAINS, BITCOIN_CHAINS_LIST, GENERIC_BITCOIN_ICON, bitcoinDiscoverer, buildBitcoinAdapter, discoverBitcoinAdapters, discoverInjectedBitcoinAdapter, resolveBitcoinCapabilities
|
|
527
|
+
export { BITCOIN_CHAINS, BITCOIN_CHAINS_LIST, GENERIC_BITCOIN_ICON, bitcoinDiscoverer, buildBitcoinAdapter, discoverBitcoinAdapters, discoverInjectedBitcoinAdapter, resolveBitcoinCapabilities };
|
|
633
528
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 = chainCount > 1`. No portable switch RPC across\n * Bitcoin wallets (Xverse/Unisat/Phantom each pick their own\n * network), so the switch is local-state-only and advertised only\n * when the wallet exposes more than one chain to switch between.\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 { 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 name: walletName,\n namespace: \"bip122\",\n reference: chainId.slice(BITCOIN_PREFIX.length),\n});\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 === null) {\n return null;\n }\n const connect = getFeature<StandardConnectFeature>(wallet, \"standard:connect\");\n if (connect === undefined) {\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) => buildAccount(a.address, chain));\n const first = built[0];\n if (first === undefined) {\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 const sendTransferTx = async (\n tx: unknown,\n account?: { walletAddress: string },\n ): Promise<string> => {\n if (sendTransfer === undefined) {\n throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:sendTransfer`);\n }\n if (\n typeof tx !== \"object\" ||\n tx === null ||\n !(\"amount\" in tx) ||\n typeof tx.amount !== \"bigint\" ||\n !(\"recipient\" in tx) ||\n typeof tx.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;\n const wsAccount = account\n ? pickAccountByAddress(wallet.accounts, account.walletAddress)\n : wallet.accounts[0];\n if (wsAccount === undefined) {\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 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 === true ? { silent: true } : undefined);\n },\n\n async disconnect() {\n if (disconnect !== undefined) {\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 === null) {\n return Promise.resolve(null);\n }\n return Promise.resolve(buildAccount(address, currentChain()));\n },\n\n getAccounts: () => {\n const chain = currentChain();\n return Promise.resolve(wallet.accounts.map((a) => buildAccount(a.address, chain)));\n },\n\n getBalance: () =>\n Promise.resolve({\n decimals: BITCOIN_DECIMALS,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n }),\n\n // Consumers wrap this in whatever Bitcoin signing library 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 getSigner: () => Promise.resolve(wallet),\n\n getTransactionReceipt: () => Promise.resolve({ status: \"Pending\" as const }),\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 sendTx: (tx, account) => sendTransferTx(tx, account),\n\n sendTxToChain: (tx, _targetChainId, account, cb) => {\n cb?.();\n return sendTransferTx(tx, account);\n },\n\n async signMessage(msg, account) {\n if (signMessage === undefined) {\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];\n if (wsAccount === undefined) {\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 === undefined\n ? {}\n : {\n async signTransaction(tx, account) {\n const wsAccount = account\n ? pickAccountByAddress(wallet.accounts, account.walletAddress)\n : wallet.accounts[0];\n if (wsAccount === undefined) {\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 subscribe(listener) {\n listeners.add(listener);\n let unsubWallet: (() => void) | null = null;\n if (events !== undefined) {\n const unsub = events.on(\"change\", (changes) => {\n if (changes.chains !== undefined) {\n const next =\n changes.chains.find((c) => c === BITCOIN_MAINNET_ID) ??\n changes.chains.find((c) => c.startsWith(BITCOIN_PREFIX));\n if (next !== undefined) {\n currentChainId = next;\n }\n }\n\n if (changes.accounts !== undefined) {\n if (changes.accounts.length === 0) {\n listener({ type: \"disconnected\" });\n return;\n }\n const chain = currentChain();\n const built = changes.accounts.map((a) => buildAccount(a.address, chain));\n const first = built[0];\n if (first === undefined) {\n return;\n }\n listener({ account: first, accounts: built, type: \"accountChanged\" });\n return;\n }\n\n if (changes.chains !== undefined) {\n notifyAccountChanged();\n }\n });\n unsubWallet = () => {\n unsub();\n };\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 // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- caller-supplied result shape for an untyped RPC bridge\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- untyped sats-connect RPC result; caller declares the shape\n return response.result as T;\n };\n\n const loadAccounts = async (): Promise<ReadonlyArray<string>> => {\n // `callRequest` only asserts the caller's shape onto an untyped RPC\n // payload, so a wallet that answers without a `result` lands here as\n // null/undefined and has to be read through an optional chain.\n const result = await callRequest<{\n addresses?: ReadonlyArray<{ address: string; purpose?: string }>;\n } | null>(\"getAccounts\", {\n message: \"Connect to butr\",\n purposes: [\"payment\", \"ordinals\"],\n });\n if (result?.addresses === undefined) {\n return [];\n }\n const addresses = result.addresses.map((a) => a.address);\n cachedAccounts = addresses;\n return addresses;\n };\n\n const sendTransferTx = async (tx: unknown): Promise<string> => {\n if (\n typeof tx !== \"object\" ||\n tx === null ||\n !(\"recipient\" in tx) ||\n typeof tx.recipient !== \"string\" ||\n !(\"amount\" in tx) ||\n typeof tx.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;\n const result = await callRequest<{ txid: string }>(\"sendTransfer\", {\n recipients: [{ address: recipient, amount: amount.toString() }],\n });\n return result.txid;\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 !== undefined) {\n return buildAccount(first, chain);\n }\n const accounts = await loadAccounts();\n const firstFresh = accounts[0];\n return firstFresh === undefined ? null : buildAccount(firstFresh, chain);\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 Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n }),\n\n getSigner: () => Promise.resolve(provider),\n\n getTransactionReceipt: () => Promise.resolve({ status: \"Pending\" as const }),\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n async requestAccounts() {\n await loadAccounts();\n },\n\n sendTx: (tx) => sendTransferTx(tx),\n\n sendTxToChain: (tx, _targetChainId, _account, cb) => {\n cb?.();\n return sendTransferTx(tx);\n },\n\n async signMessage(msg) {\n const address = cachedAccounts[0];\n if (address === undefined) {\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 toStringArray = (value: unknown): Array<string> =>\n Array.isArray(value) ? value.filter((item): item is string => typeof item === \"string\") : [];\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 sendBitcoinTx = (tx: unknown): Promise<string> => {\n if (typeof provider.sendBitcoin !== \"function\") {\n throw new TypeError(`Wallet ${name} does not expose sendBitcoin`);\n }\n if (\n typeof tx !== \"object\" ||\n tx === null ||\n !(\"recipient\" in tx) ||\n typeof tx.recipient !== \"string\" ||\n !(\"amount\" in tx) ||\n typeof tx.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;\n return provider.sendBitcoin(recipient, Number(amount));\n };\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 void 0;\n }\n };\n\n return {\n capabilities: CAPS_UNISAT,\n chainPlatform: \"bitcoin\",\n\n async connect(opts) {\n if (opts?.silent === true) {\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 Promise.resolve(),\n\n async getAccount() {\n const accounts = await provider.getAccounts();\n const first = accounts[0];\n if (first === undefined) {\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 Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n }),\n\n getSigner: () => Promise.resolve(provider),\n\n getTransactionReceipt: () => Promise.resolve({ status: \"Pending\" as const }),\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) => sendBitcoinTx(tx),\n\n sendTxToChain: (tx, _targetChainIdDecimal, _account, cb) => {\n cb?.();\n return sendBitcoinTx(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 = toStringArray(args[0]);\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 === undefined) {\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 if (target !== undefined) {\n return target;\n }\n if (typeof window === \"undefined\") {\n return null;\n }\n // `window` carries the injected wallet globals (`unisat`, `okxwallet`,\n // etc.) as an untyped host object; `InjectedHost` names the four keys\n // butr probes, all optional and read defensively in `probeProviders`.\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- untyped injected-wallet window globals\n return window as unknown as InjectedHost;\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?.() === true) {\n return;\n }\n const host = readHost(options.target);\n if (host === null) {\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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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/capabilities.ts","../src/wallet-standard-adapter.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\";\nimport { buildWalletCapabilities } from \"@usebutr/wallet-standard-shared\";\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 feature → butr capability mapping. The flags that hold for every\n * namespace are documented on `buildWalletCapabilities`.\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 */\nconst resolveBitcoinCapabilities = (input: BitcoinCapabilityInput): WalletCapabilities =>\n buildWalletCapabilities({\n chainCount: input.chainCount,\n events: input.features.events,\n sendTransaction: input.features.sendTransfer,\n signIn: false,\n signMessage: input.features.signMessage,\n signTransaction: input.features.signPsbt,\n });\n\nexport type { BitcoinCapabilityInput };\nexport { resolveBitcoinCapabilities };\n","import type { WalletAdapter } from \"@usebutr/core\";\nimport {\n createWalletStandardCore,\n discoverWalletStandard,\n getFeature,\n slugify,\n} from \"@usebutr/wallet-standard-shared\";\nimport type { WalletStandardWallet } 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\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 core = createWalletStandardCore({\n chainPrefix: BITCOIN_PREFIX,\n id: slugify(\"btc\", wallet.name),\n label: \"Bitcoin\",\n namespace: \"bip122\",\n platform: \"Bitcoin\",\n preferredChainIds: [BITCOIN_MAINNET_ID],\n registerDisconnector,\n trackChainChanges: true,\n wallet,\n });\n if (core === null) {\n return null;\n }\n\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 const sendTransferTx = async (\n tx: unknown,\n account?: { walletAddress: string },\n ): Promise<string> => {\n if (sendTransfer === undefined) {\n throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:sendTransfer`);\n }\n if (\n typeof tx !== \"object\" ||\n tx === null ||\n !(\"amount\" in tx) ||\n typeof tx.amount !== \"bigint\" ||\n !(\"recipient\" in tx) ||\n typeof tx.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;\n const output = await sendTransfer.sendTransfer({\n account: core.resolveAccount(account),\n amount,\n chain: core.currentChainId(),\n recipient,\n });\n return output.txid;\n };\n\n return {\n ...core,\n capabilities: resolveBitcoinCapabilities({\n chainCount: core.chainCount,\n features: {\n events: core.hasEvents,\n sendTransfer: Boolean(sendTransfer),\n signMessage: Boolean(signMessage),\n signPsbt: Boolean(signPsbt),\n },\n }),\n chainPlatform: \"bitcoin\",\n\n getBalance: () =>\n Promise.resolve({\n decimals: BITCOIN_DECIMALS,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n }),\n\n getTransactionReceipt: () => Promise.resolve({ status: \"Pending\" as const }),\n\n async requestAccounts() {\n await core.connect();\n },\n\n sendTx: (tx, account) => sendTransferTx(tx, account),\n\n sendTxToChain: (tx, _targetChainId, account, cb) => {\n cb?.();\n return sendTransferTx(tx, account);\n },\n\n async signMessage(msg, account) {\n if (signMessage === undefined) {\n throw new Error(`Wallet ${wallet.name} does not advertise bitcoin:signMessage`);\n }\n const output = await signMessage.signMessage({\n account: core.resolveAccount(account),\n message: msg,\n });\n return { signature: output.signature, signedMessage: output.signedMessage };\n },\n\n ...(signPsbt === undefined\n ? {}\n : {\n async signTransaction(tx, account) {\n const wsAccount = core.resolveAccount(account);\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: core.currentChainId(),\n psbt: tx,\n });\n return output.signedPsbt;\n },\n }),\n };\n};\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 { buildBitcoinAdapter, 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 // oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- caller-supplied result shape for an untyped RPC bridge\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 // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- untyped sats-connect RPC result; caller declares the shape\n return response.result as T;\n };\n\n const loadAccounts = async (): Promise<ReadonlyArray<string>> => {\n // `callRequest` only asserts the caller's shape onto an untyped RPC\n // payload, so a wallet that answers without a `result` lands here as\n // null/undefined and has to be read through an optional chain.\n const result = await callRequest<{\n addresses?: ReadonlyArray<{ address: string; purpose?: string }>;\n } | null>(\"getAccounts\", {\n message: \"Connect to butr\",\n purposes: [\"payment\", \"ordinals\"],\n });\n if (result?.addresses === undefined) {\n return [];\n }\n const addresses = result.addresses.map((a) => a.address);\n cachedAccounts = addresses;\n return addresses;\n };\n\n const sendTransferTx = async (tx: unknown): Promise<string> => {\n if (\n typeof tx !== \"object\" ||\n tx === null ||\n !(\"recipient\" in tx) ||\n typeof tx.recipient !== \"string\" ||\n !(\"amount\" in tx) ||\n typeof tx.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;\n const result = await callRequest<{ txid: string }>(\"sendTransfer\", {\n recipients: [{ address: recipient, amount: amount.toString() }],\n });\n return result.txid;\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 !== undefined) {\n return buildAccount(first, chain);\n }\n const accounts = await loadAccounts();\n const firstFresh = accounts[0];\n return firstFresh === undefined ? null : buildAccount(firstFresh, chain);\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 Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n }),\n\n getSigner: () => Promise.resolve(provider),\n\n getTransactionReceipt: () => Promise.resolve({ status: \"Pending\" as const }),\n\n icon: GENERIC_BITCOIN_ICON,\n id,\n name,\n\n async requestAccounts() {\n await loadAccounts();\n },\n\n sendTx: (tx) => sendTransferTx(tx),\n\n sendTxToChain: (tx, _targetChainId, _account, cb) => {\n cb?.();\n return sendTransferTx(tx);\n },\n\n async signMessage(msg) {\n const address = cachedAccounts[0];\n if (address === undefined) {\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 toStringArray = (value: unknown): Array<string> =>\n Array.isArray(value) ? value.filter((item): item is string => typeof item === \"string\") : [];\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 sendBitcoinTx = (tx: unknown): Promise<string> => {\n if (typeof provider.sendBitcoin !== \"function\") {\n throw new TypeError(`Wallet ${name} does not expose sendBitcoin`);\n }\n if (\n typeof tx !== \"object\" ||\n tx === null ||\n !(\"recipient\" in tx) ||\n typeof tx.recipient !== \"string\" ||\n !(\"amount\" in tx) ||\n typeof tx.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;\n return provider.sendBitcoin(recipient, Number(amount));\n };\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 void 0;\n }\n };\n\n return {\n capabilities: CAPS_UNISAT,\n chainPlatform: \"bitcoin\",\n\n async connect(opts) {\n if (opts?.silent === true) {\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 Promise.resolve(),\n\n async getAccount() {\n const accounts = await provider.getAccounts();\n const first = accounts[0];\n if (first === undefined) {\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 Promise.resolve({\n decimals: 8,\n formatted: \"0\",\n symbol: \"BTC\",\n value: 0n,\n }),\n\n getSigner: () => Promise.resolve(provider),\n\n getTransactionReceipt: () => Promise.resolve({ status: \"Pending\" as const }),\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) => sendBitcoinTx(tx),\n\n sendTxToChain: (tx, _targetChainIdDecimal, _account, cb) => {\n cb?.();\n return sendBitcoinTx(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 = toStringArray(args[0]);\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 === undefined) {\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 if (target !== undefined) {\n return target;\n }\n if (typeof window === \"undefined\") {\n return null;\n }\n // `window` carries the injected wallet globals (`unisat`, `okxwallet`,\n // etc.) as an untyped host object; `InjectedHost` names the four keys\n // butr probes, all optional and read defensively in `probeProviders`.\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- untyped injected-wallet window globals\n return window as unknown as InjectedHost;\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?.() === true) {\n return;\n }\n const host = readHost(options.target);\n if (host === null) {\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-adapter\";\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 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.
|
|
3
|
+
"version": "1.0.0",
|
|
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,8 +25,8 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@usebutr/core": "0.
|
|
29
|
-
"@usebutr/wallet-standard-shared": "0.
|
|
28
|
+
"@usebutr/core": "1.0.0",
|
|
29
|
+
"@usebutr/wallet-standard-shared": "0.4.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@wallet-standard/app": "^1.1.1",
|