@usebutr/evm 1.1.1 → 2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @usebutr/evm
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#203](https://github.com/pedroapfilho/usebutr/pull/203) [`1263f86`](https://github.com/pedroapfilho/usebutr/commit/1263f8666afd43b4f7dbf8df1763709c3edf09d9) Thanks [@pedroapfilho](https://github.com/pedroapfilho)! - Adapters now say what they can do by having the method: `capabilities` is gone, and an optional method (`sendTx`, `signMessage`, `getBalance`, `switchChain`, …) exists only when it works for that wallet. No adapter returns a placeholder balance or a receipt that stays pending anymore.
8
+
9
+ - `sendTx(tx, { account, chain })` replaces `sendTx` and `sendTxToChain`, and `signMessage`, `signTransaction` and `getBalance` take options objects. `chain` is a `ChainBase`. An adapter either routes the call to that chain, switches the wallet to it, or rejects; none ignores it.
10
+ - An `account` the wallet does not expose now rejects instead of signing with the first account. `chain.name` is the chain's name, never the wallet's.
11
+ - `getAccounts()` resolves the active account first. `getAccount` and `switchAccount` are removed.
12
+ - `getSigner()` resolves a tagged `WalletSigner` (`eip1193`, `wallet-standard`, `walletconnect`, `ledger-*`, …), so it can be narrowed with `switch (signer.kind)` instead of cast.
13
+ - `createWalletManager(config, { initialState })` owns discovery, hydration and persistence, and works without React. `config.sources` replaces the `discovery`, `connectors` and `createConnector` props. `fromAdapters` registers WalletConnect, Ledger and hand-built adapters, which now also appear in `useDiscoveredWallets()`.
14
+ - `WalletManagerProvider` takes `config` and `initialState`. `useSigner(wallet)` and `useBalance(wallet, { token, account })` take the wallet entry itself, and id-taking hooks read the active wallet only when the id is omitted (`null` reads none). The hooks are `useWalletManager`, `useWalletState`, `useConnect`, `useWallet`, `useSelectedWallet` (now typed per platform), `useAccounts`, `useConnectionStatus`, `useIsHydrated`, `useIsReconnecting`, `useDiscoveredWallets`, `useConnectedWallets`, the `…ByPlatform` groupings, `useBalance` and `useSigner`.
15
+ - `manager.connect()` and `useConnect().connectAsync()` resolve the `ConnectedWallet` and reject with a `ConnectionError`, now an `Error` subclass with a `kind` and a new `WalletNotFound` kind. `useConnect().connect()` never rejects: the failure lands in its `error`.
16
+ - `WalletPersistence` is `load()` / `save(state)`, and `createWalletStorage` replaces `new WalletStorage`. Storage keys are unchanged.
17
+ - Chain registries (`EVM_CHAINS`, `SVM_CHAINS`, …, `CHAINS_BY_PLATFORM`) move to `@usebutr/core`, and `BITCOIN_CHAINS` gains `testnet4`. `@usebutr/wallets` loads every platform's signer kinds, so an app that imports only it can narrow `signer.kind`.
18
+ - `@usebutr/react` requires React 19, which its `use()` call already needed.
19
+ - WalletConnect requests on Solana, Sui and Bitcoin now carry their chain, so they no longer fall through to the first namespace in a multi-namespace session. Solana takes `SVM_CHAINS` chains and maps them to the genesis-hash ids WalletConnect sessions use.
20
+ - Ledger's Solana `signTransaction` returns the full signed transaction, Sui signs the intent message, and Bitcoin `signMessage` returns a BIP-137 signature.
21
+ - `@usebutr/testing`'s fake adapter resolves a `signer` you pass instead of registering a test-only signer kind.
22
+ - `setAccount` selects an exposed account without changing any account's chain. Unknown accounts are ignored; chain changes come from the adapter.
23
+ - WalletConnect EVM events use the namespace in `session_event`, including empty account lists that end the connection. Local chain switches still update the manager.
24
+ - Failed persistence saves wait for every key write to finish before reporting failure, so delayed writes cannot overwrite a later disconnect.
25
+ - `@usebutr/svm/transaction` provides the shared legacy/v0 signing codec used by Ledger and WalletConnect, with consistent layout and signature validation.
26
+
27
+ See the migration guide at https://docs.usebutr.com/migration.
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [[`1263f86`](https://github.com/pedroapfilho/usebutr/commit/1263f8666afd43b4f7dbf8df1763709c3edf09d9), [`5d1f234`](https://github.com/pedroapfilho/usebutr/commit/5d1f23403263f7a1f8a48be061727972fe749b5f)]:
32
+ - @usebutr/core@3.0.0
33
+
3
34
  ## 1.1.1
4
35
 
5
36
  ### Patch Changes
package/README.md CHANGED
@@ -11,22 +11,38 @@ connection-state library. Your application owns the picker UI and chain client.
11
11
  npm install @usebutr/react @usebutr/core @usebutr/evm zustand
12
12
  ```
13
13
 
14
- React 18+ is a peer dependency of the provider. Discovery does not render a connect modal; add your picker as the provider child.
14
+ React 19 is a peer dependency of the provider. Discovery does not render a connect modal; add your picker as the provider child. `discoverEvmAdapters` (EIP-6963) and `discoverInjectedAdapter` (the legacy `window.ethereum` fallback) are wallet sources as-is; `autoDiscovery()` from `@usebutr/wallets` combines both with the other platforms.
15
15
 
16
16
  ## Usage
17
17
 
18
18
  ```tsx
19
19
  import type { ReactNode } from "react";
20
- import { createWalletSource } from "@usebutr/core";
20
+ import type { WalletManagerConfig } from "@usebutr/core";
21
21
  import { discoverEvmAdapters } from "@usebutr/evm";
22
22
  import { WalletManagerProvider } from "@usebutr/react";
23
23
 
24
- const discovery = createWalletSource(discoverEvmAdapters);
24
+ const config: WalletManagerConfig = { sources: [discoverEvmAdapters] };
25
+
25
26
  export const WalletProvider = ({ children }: { children: ReactNode }) => (
26
- <WalletManagerProvider discovery={discovery}>{children}</WalletManagerProvider>
27
+ <WalletManagerProvider config={config}>{children}</WalletManagerProvider>
27
28
  );
28
29
  ```
29
30
 
31
+ Every EVM adapter defines `requestAccounts`, `switchChain`, `signMessage`, `sendTx`, `getBalance`, `getTransactionReceipt` and `subscribe`. `getSigner()` resolves `{ kind: "eip1193", provider }` for your own viem or ethers client. Chain registries (`EVM_CHAINS`, `EVM_CHAINS_LIST`) live in `@usebutr/core`.
32
+
33
+ ```ts
34
+ import type { ConnectedWallet } from "@usebutr/core";
35
+ import { EVM_CHAINS } from "@usebutr/core";
36
+
37
+ // `sendTx` switches the wallet to `chain` first when it is elsewhere, and
38
+ // sends from `account`, which must be one the wallet exposes.
39
+ export const pay = (wallet: ConnectedWallet<"evm">, to: string) =>
40
+ wallet.connector.sendTx?.(
41
+ { to, value: 10_000_000_000_000_000n },
42
+ { account: wallet.account, chain: EVM_CHAINS.base },
43
+ );
44
+ ```
45
+
30
46
  ## Documentation
31
47
 
32
48
  - [Package reference](https://docs.usebutr.com/api/evm)
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ChainBase, PlatformDiscoverer, WalletAdapter, WalletCapabilities, WalletSigner, bytesToHexPrefixed as bytesToHex, hexToBytes } from "@usebutr/core";
1
+ import { EvmAdapter, PlatformDiscoverer } from "@usebutr/core";
2
2
  //#region src/eip1193.d.ts
3
3
  /**
4
4
  * Declared inline rather than taken from `viem`, which would expand butr's
@@ -39,7 +39,7 @@ type Eip6963AnnounceEvent = CustomEvent<Eip6963ProviderDetail>;
39
39
  //#region src/eip6963.d.ts
40
40
  declare const ANNOUNCE_EVENT = "eip6963:announceProvider";
41
41
  declare const REQUEST_EVENT = "eip6963:requestProvider";
42
- type AdapterCallback = (adapter: WalletAdapter, info: Eip6963ProviderInfo) => void;
42
+ type AdapterCallback = (adapter: EvmAdapter, info: Eip6963ProviderInfo) => void;
43
43
  type DiscoverOptions = {
44
44
  /** Event target to listen on. Defaults to `window` in browser/RN/
45
45
  * SSR'd environments; tests can pass a fresh `new EventTarget()` to
@@ -64,7 +64,7 @@ declare const chainIdDecimalToHex: (dec: string) => string;
64
64
  * implement and silently ignore, so their own auto-reconnect may outlive it.
65
65
  * `getBalance()` labels the native balance `"ETH"` on every EVM chain.
66
66
  */
67
- declare const buildEvmAdapter: (info: Eip6963ProviderInfo, provider: Eip1193Provider) => WalletAdapter;
67
+ declare const buildEvmAdapter: (info: Eip6963ProviderInfo, provider: Eip1193Provider) => EvmAdapter;
68
68
  //#endregion
69
69
  //#region src/injected.d.ts
70
70
  /**
@@ -95,72 +95,16 @@ declare global {
95
95
  ethereum?: Partial<Eip1193Provider>;
96
96
  }
97
97
  }
98
- declare const isEip1193Provider: (value: WalletSigner | undefined) => value is Eip1193Provider;
98
+ /** Structural check for code that holds a provider of unknown origin, such
99
+ * as `window.ethereum`. A butr signer narrows on `kind === "eip1193"`
100
+ * instead. */
101
+ declare const isEip1193Provider: (value: unknown) => value is Eip1193Provider;
99
102
  /**
100
103
  * Last-resort path for the long tail of EVM wallets that expose only
101
104
  * `window.ethereum` and never announce via EIP-6963. The emitted adapter
102
105
  * carries `rdns: "injected:legacy"` so consumers can tell it apart.
103
106
  */
104
- declare const discoverInjectedAdapter: (onAdapter: (adapter: WalletAdapter) => void, options?: InjectedDiscoveryOptions) => (() => void);
105
- //#endregion
106
- //#region src/chains.d.ts
107
- /**
108
- * Common EVM chain registry keyed by CAIP-2 id. Useful for chain-
109
- * switcher UIs. butr itself doesn't read this: `Connector.switchChain`
110
- * accepts any `ChainBase`.
111
- */
112
- declare const EVM_CHAINS: {
113
- readonly arbitrum: {
114
- readonly id: "eip155:42161";
115
- readonly name: "Arbitrum One";
116
- readonly namespace: "eip155";
117
- readonly reference: "42161";
118
- };
119
- readonly base: {
120
- readonly id: "eip155:8453";
121
- readonly name: "Base";
122
- readonly namespace: "eip155";
123
- readonly reference: "8453";
124
- };
125
- readonly bsc: {
126
- readonly id: "eip155:56";
127
- readonly name: "BNB Smart Chain";
128
- readonly namespace: "eip155";
129
- readonly reference: "56";
130
- };
131
- readonly ethereum: {
132
- readonly id: "eip155:1";
133
- readonly name: "Ethereum";
134
- readonly namespace: "eip155";
135
- readonly reference: "1";
136
- };
137
- readonly optimism: {
138
- readonly id: "eip155:10";
139
- readonly name: "Optimism";
140
- readonly namespace: "eip155";
141
- readonly reference: "10";
142
- };
143
- readonly polygon: {
144
- readonly id: "eip155:137";
145
- readonly name: "Polygon";
146
- readonly namespace: "eip155";
147
- readonly reference: "137";
148
- };
149
- readonly sepolia: {
150
- readonly id: "eip155:11155111";
151
- readonly name: "Sepolia";
152
- readonly namespace: "eip155";
153
- readonly reference: "11155111";
154
- };
155
- };
156
- declare const EVM_CHAINS_LIST: ReadonlyArray<ChainBase>;
157
- //#endregion
158
- //#region src/capabilities.d.ts
159
- declare const EIP6963_RDNS_WITH_REQUEST_ACCOUNTS: Set<string>;
160
- type Eip6963CapabilityInput = {
161
- rdns: string;
162
- };
163
- declare const resolveEip6963Capabilities: (input: Eip6963CapabilityInput) => WalletCapabilities;
107
+ declare const discoverInjectedAdapter: (onAdapter: (adapter: EvmAdapter) => void, options?: InjectedDiscoveryOptions) => (() => void);
164
108
  //#endregion
165
109
  //#region src/discoverer.d.ts
166
110
  /**
@@ -170,16 +114,15 @@ declare const resolveEip6963Capabilities: (input: Eip6963CapabilityInput) => Wal
170
114
  declare const evmDiscoverer: PlatformDiscoverer;
171
115
  //#endregion
172
116
  //#region src/signer-augmentation.d.ts
173
- /**
174
- * `getSigner()` itself still returns `Promise<unknown>` (see
175
- * `packages/core/src/types/signer.ts` for why); this only changes what
176
- * `SignerForPlatform["evm"]` evaluates to.
177
- */
117
+ /** Every EVM adapter built on an EIP-1193 provider (injected, EIP-6963,
118
+ * WalletConnect's EVM namespace) hands back that provider. */
178
119
  declare module "@usebutr/core" {
179
- interface SignerForPlatform {
180
- evm: Eip1193Provider;
120
+ interface WalletSignerRegistry {
121
+ eip1193: {
122
+ provider: Eip1193Provider;
123
+ };
181
124
  }
182
125
  }
183
126
  //#endregion
184
- export { ANNOUNCE_EVENT, EIP6963_RDNS_WITH_REQUEST_ACCOUNTS, EVM_CHAINS, EVM_CHAINS_LIST, type Eip1193Listener, type Eip1193Object, type Eip1193Provider, type Eip1193RequestArgs, type Eip1193Value, type Eip6963AnnounceEvent, type Eip6963CapabilityInput, type Eip6963ProviderDetail, type Eip6963ProviderInfo, GENERIC_INJECTED_ICON, type InjectedDiscoveryOptions, REQUEST_EVENT, buildEvmAdapter, bytesToHex, chainIdDecimalToHex, chainIdHexToDecimal, discoverEvmAdapters, discoverInjectedAdapter, evmDiscoverer, formatEther, hexToBytes, isEip1193Provider, resolveEip6963Capabilities };
127
+ export { ANNOUNCE_EVENT, type Eip1193Listener, type Eip1193Object, type Eip1193Provider, type Eip1193RequestArgs, type Eip1193Value, type Eip6963AnnounceEvent, type Eip6963ProviderDetail, type Eip6963ProviderInfo, GENERIC_INJECTED_ICON, type InjectedDiscoveryOptions, REQUEST_EVENT, buildEvmAdapter, chainIdDecimalToHex, chainIdHexToDecimal, discoverEvmAdapters, discoverInjectedAdapter, evmDiscoverer, formatEther, isEip1193Provider };
185
128
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/eip1193.ts","../src/eip6963.ts","../src/evm-balance.ts","../src/eip6963-adapter.ts","../src/injected.ts","../src/chains.ts","../src/capabilities.ts","../src/discoverer.ts","../src/signer-augmentation.ts"],"mappings":";;;;;;;KAMK;GAAmB,cAAc;;KACjC,2DAMD,aACA,cAAc,gBACd;KAEC;EACH;EACA,SAAS,cAAc,gBAAgB;;KAGpC,sBAAsB,MAAM,cAAc;KAE1C;EACH,KAAK,eAAe,UAAU;EAC9B,iBAAiB,eAAe,UAAU;EAC1C,UAAU,MAAM,uBAAuB,QAAQ;;KAG5C;;EAEH;;EAEA;;;EAGA;;EAEA;;KAGG;EACH,MAAM;EACN,UAAU;;KAGP,uBAAuB,YAAY;;;cC1ClC;cACA;KAED,mBAAmB,SAAS,eAAe,MAAM;KAEjD;;;;EAIH,SAAS;;;;;;;cAiDL,sBAAmB,WACZ,iBAAe,UACjB;;;cChCL,cAAW;;;cC0BX,sBAAmB;cACnB,sBAAmB;;;;;;cAoDnB,kBAAe,MAAU,qBAAmB,UAAY,oBAAkB;;;;;;;;cCtG1E;KAKD;;;;;;EAMH;;;;;EAKA;;EAEA;IAAW,WAAW,QAAQ;;;QAGxB;YAEI;IACR,WAAW,QAAQ;;;cAIjB,oBAAiB,OAAW,6BAA2B,SAAS;;;;;;cAmBhE,0BAAuB,YACf,SAAS,wBAAsB,UAClC;;;;;;;;cCpDL;;aAEF;aACA;aACA;aACA;;;aAEM;aAAmB;aAAc;aAAqB;;;aACvD;aAAiB;aAAyB;aAAqB;;;aAC1D;aAAgB;aAAkB;aAAqB;;;aACvD;aAAiB;aAAkB;aAAqB;;;aACzD;aAAkB;aAAiB;aAAqB;;;aACxD;aAAuB;aAAiB;aAAqB;;;cAGpE,iBAAiB,cAAc;;;cCpB/B,oCAAkC;KAInC;EAA2B;;cAE1B,6BAA0B,OAAW,2BAAyB;;;;;;;cCC9D,eAAe;;;;;;;;;YCAT;IACR,KAAK"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/eip1193.ts","../src/eip6963.ts","../src/evm-balance.ts","../src/eip6963-adapter.ts","../src/injected.ts","../src/discoverer.ts","../src/signer-augmentation.ts"],"mappings":";;;;;;;KAMK;GAAmB,cAAc;;KACjC,2DAMD,aACA,cAAc,gBACd;KAEC;EACH;EACA,SAAS,cAAc,gBAAgB;;KAGpC,sBAAsB,MAAM,cAAc;KAE1C;EACH,KAAK,eAAe,UAAU;EAC9B,iBAAiB,eAAe,UAAU;EAC1C,UAAU,MAAM,uBAAuB,QAAQ;;KAG5C;;EAEH;;EAEA;;;EAGA;;EAEA;;KAGG;EACH,MAAM;EACN,UAAU;;KAGP,uBAAuB,YAAY;;;cC1ClC;cACA;KAED,mBAAmB,SAAS,YAAY,MAAM;KAE9C;;;;EAIH,SAAS;;;;;;;cAmDL,sBAAmB,WACZ,iBAAe,UACjB;;;cClCL,cAAW;;;cCUX,sBAAmB;cACnB,sBAAmB;;;;;;cAyCnB,kBAAe,MAAU,qBAAmB,UAAY,oBAAkB;;;;;;;;cC3E1E;KAKD;;;;;;EAMH;;;;;EAKA;;EAEA;IAAW,WAAW,QAAQ;;;QAGxB;YAEI;IACR,WAAW,QAAQ;;;;;;cAOjB,oBAAiB,mBAAqB,SAAS;;;;;;cAoB/C,0BAAuB,YACf,SAAS,qBAAmB,UAC/B;;;;;;;cCtDL,eAAe;;;;;;YCHT;IACR;MAAW,UAAU"}
package/dist/index.js CHANGED
@@ -1,21 +1,5 @@
1
- import { bytesToHexPrefixed, bytesToHexPrefixed as bytesToHex, hexToBytes, hexToBytes as hexToBytes$1, sanitizeIcon } from "@usebutr/core";
1
+ import { EVM_CHAINS_LIST, buildAccount, bytesToHexPrefixed, hexToBytes, resolveChain, sanitizeIcon } from "@usebutr/core";
2
2
 
3
- //#region src/capabilities.ts
4
- const EIP6963_RDNS_WITH_REQUEST_ACCOUNTS = /* @__PURE__ */ new Set(["io.metamask"]);
5
- const resolveEip6963Capabilities = (input) => ({
6
- getBalance: true,
7
- getTransactionReceipt: true,
8
- requestAccounts: EIP6963_RDNS_WITH_REQUEST_ACCOUNTS.has(input.rdns),
9
- sendTransaction: true,
10
- signIn: false,
11
- signMessage: true,
12
- signTransaction: false,
13
- subscribe: true,
14
- switchAccount: false,
15
- switchChain: true
16
- });
17
-
18
- //#endregion
19
3
  //#region src/eip1193.ts
20
4
  /** `provider.request` is typed `unknown` by design; these helpers narrow
21
5
  * the well-known EVM RPC shapes at the boundary with runtime guards so
@@ -33,7 +17,7 @@ const requestStringArray = async (provider, args) => {
33
17
 
34
18
  //#endregion
35
19
  //#region src/evm-balance.ts
36
- const HEX_PREFIX$1 = "0x";
20
+ const HEX_PREFIX = "0x";
37
21
  const ETH_DECIMALS = 18n;
38
22
  const ERC20_BALANCE_OF_SELECTOR = "0x70a08231";
39
23
  const ERC20_DECIMALS_SELECTOR = "0x313ce567";
@@ -54,14 +38,14 @@ const formatUnits = (raw, decimals) => {
54
38
  const formatEther = (wei) => formatUnits(wei, Number(ETH_DECIMALS));
55
39
  const padAddressForCall = (address) => address.replace(new RegExp("^0x", "v"), "").toLowerCase().padStart(64, "0");
56
40
  const decodeAbiString = (hex) => {
57
- const clean = hex.startsWith(HEX_PREFIX$1) ? hex.slice(2) : hex;
41
+ const clean = hex.startsWith(HEX_PREFIX) ? hex.slice(2) : hex;
58
42
  if (clean.length === 0) return "";
59
43
  if (clean.length >= 128) {
60
44
  const lengthHex = clean.slice(64, 128);
61
45
  const length = Number(BigInt(`0x${lengthHex}`));
62
- if (length > 0 && clean.length >= 128 + length * 2) return new TextDecoder().decode(hexToBytes$1(clean.slice(128, 128 + length * 2)));
46
+ if (length > 0 && clean.length >= 128 + length * 2) return new TextDecoder().decode(hexToBytes(clean.slice(128, 128 + length * 2)));
63
47
  }
64
- const bytes = hexToBytes$1(clean.slice(0, 64));
48
+ const bytes = hexToBytes(clean.slice(0, 64));
65
49
  let end = bytes.length;
66
50
  while (end > 0 && bytes[end - 1] === 0) end -= 1;
67
51
  return new TextDecoder().decode(bytes.subarray(0, end));
@@ -115,69 +99,73 @@ const readEvmBalance = async (provider, address, tokenAddress) => {
115
99
 
116
100
  //#endregion
117
101
  //#region src/eip6963-adapter.ts
118
- const HEX_PREFIX = "0x";
102
+ const EVM_NAMESPACE = "eip155";
119
103
  const toStringArray = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
120
- const toEip1193Value = (value) => {
121
- if (typeof value === "function") throw new TypeError("EVM transactions cannot contain functions");
122
- if (Array.isArray(value)) return value.map(toEip1193Value);
123
- if (value instanceof Uint8Array) return value;
124
- if (typeof value === "object" && value !== null) {
125
- const result = {};
126
- for (const [key, nested] of Object.entries(value)) result[key] = nested === void 0 ? void 0 : toEip1193Value(nested);
127
- return result;
128
- }
129
- return value;
130
- };
131
- const withFrom = (tx, from) => {
132
- if (typeof tx === "string" || tx instanceof Uint8Array) return tx;
104
+ /** JSON-RPC cannot carry a `bigint`, so quantities go out as `0x` hex. */
105
+ const encodeValue = (value) => {
106
+ if (typeof value === "bigint") return `0x${value.toString(16)}`;
107
+ if (Array.isArray(value)) return value.map(encodeValue);
108
+ if (typeof value !== "object" || value === null) return value;
133
109
  const result = {};
134
- for (const [key, value] of Object.entries(tx)) result[key] = value === void 0 ? void 0 : toEip1193Value(value);
135
- if (from !== void 0) result.from = from;
110
+ for (const [key, nested] of Object.entries(value)) result[key] = nested === void 0 ? void 0 : encodeValue(nested);
136
111
  return result;
137
112
  };
138
113
  const chainIdHexToDecimal = (hex) => BigInt(hex).toString(10);
139
- const chainIdDecimalToHex = (dec) => `${HEX_PREFIX}${BigInt(dec).toString(16)}`;
140
- const buildEvmChain = (chainIdHex, walletName) => {
141
- const reference = chainIdHexToDecimal(chainIdHex);
142
- return {
143
- id: `eip155:${reference}`,
144
- name: walletName,
145
- namespace: "eip155",
146
- reference
147
- };
148
- };
149
- const buildEvmAccount = (address, chain) => ({
150
- chain,
151
- id: `${chain.id}:${address.toLowerCase()}`,
152
- walletAddress: address
153
- });
154
- /** Rejections propagate: `getAccount`/`getAccounts` surface the wallet's
155
- * own provider error, while the `subscribe` bridge swallows it because a
156
- * later event retries synchronization. */
157
- const readAccountState = async (provider, walletName, options = {}) => {
158
- const accounts = options.accounts ?? await requestStringArray(provider, { method: "eth_accounts" });
159
- if (accounts.length === 0) return null;
160
- const chainIdHex = options.chainIdHex ?? await requestString(provider, { method: "eth_chainId" });
114
+ const chainIdDecimalToHex = (dec) => `0x${BigInt(dec).toString(16)}`;
115
+ const evmChainFromHex = (chainIdHex) => resolveChain(`${EVM_NAMESPACE}:${chainIdHexToDecimal(chainIdHex)}`, EVM_CHAINS_LIST);
116
+ /** Rejections propagate: `getAccounts` surfaces the wallet's own provider
117
+ * error, while the `subscribe` bridge swallows it because a later event
118
+ * retries synchronization. */
119
+ const readAccounts = async (provider, known = {}) => {
120
+ const addresses = known.addresses ?? await requestStringArray(provider, { method: "eth_accounts" });
121
+ if (addresses.length === 0) return [];
122
+ const chainIdHex = known.chainIdHex ?? await requestString(provider, { method: "eth_chainId" });
161
123
  if (chainIdHex === null) throw new Error("Wallet returned a malformed eth_chainId response");
162
- const chain = buildEvmChain(chainIdHex, walletName);
163
- const builtAccounts = accounts.map((address) => buildEvmAccount(address, chain));
164
- const account = builtAccounts[0];
165
- return account === void 0 ? null : {
166
- account,
167
- accounts: builtAccounts
168
- };
124
+ const chain = evmChainFromHex(chainIdHex);
125
+ return addresses.map((address) => buildAccount(address, chain));
169
126
  };
127
+ /** EIP-1474 / JSON-RPC codes wallets use for an unimplemented method.
128
+ * Coinbase wraps its own -32604 inside a -32603 `data.originalError`. */
129
+ const METHOD_NOT_SUPPORTED_CODES = /* @__PURE__ */ new Set([
130
+ 4200,
131
+ -32601,
132
+ -32603,
133
+ -32604
134
+ ]);
170
135
  /**
171
136
  * `disconnect` calls `wallet_revokePermissions`, which many wallets don't
172
137
  * implement and silently ignore, so their own auto-reconnect may outlive it.
173
138
  * `getBalance()` labels the native balance `"ETH"` on every EVM chain.
174
139
  */
175
140
  const buildEvmAdapter = (info, provider) => {
141
+ /** The address to act as, in the wallet's own casing. Hex addresses are
142
+ * case-insensitive (EIP-55 casing is only a checksum), so they compare
143
+ * lowercased. */
144
+ const resolveAddress = async (account) => {
145
+ const exposed = await requestStringArray(provider, { method: "eth_accounts" });
146
+ if (account === void 0) {
147
+ const active = exposed.at(0);
148
+ if (active === void 0) throw new Error(`Wallet ${info.name} has no connected account`);
149
+ return active;
150
+ }
151
+ const wanted = account.walletAddress.toLowerCase();
152
+ const match = exposed.find((address) => address.toLowerCase() === wanted);
153
+ if (match === void 0) throw new Error(`Wallet ${info.name} does not expose account ${account.walletAddress}`);
154
+ return match;
155
+ };
156
+ const switchChain = async (chain) => {
157
+ if (chain.namespace !== EVM_NAMESPACE || !new RegExp("^\\d+$", "v").test(chain.reference)) throw new Error(`EVM adapter received non-EVM chain "${chain.id}". Pass a chain with namespace "${EVM_NAMESPACE}" and a numeric reference.`);
158
+ const target = chainIdDecimalToHex(chain.reference);
159
+ if ((await requestString(provider, { method: "eth_chainId" }))?.toLowerCase() === target) return;
160
+ await provider.request({
161
+ method: "wallet_switchEthereumChain",
162
+ params: [{ chainId: target }]
163
+ });
164
+ };
176
165
  return {
177
- capabilities: resolveEip6963Capabilities({ rdns: info.rdns }),
178
166
  chainPlatform: "evm",
179
- async connect(opts) {
180
- if (opts?.silent === true) {
167
+ async connect(options) {
168
+ if (options?.silent === true) {
181
169
  if ((await requestStringArray(provider, { method: "eth_accounts" })).length === 0) throw new Error("No authorized accounts for silent reconnect");
182
170
  return;
183
171
  }
@@ -191,22 +179,18 @@ const buildEvmAdapter = (info, provider) => {
191
179
  });
192
180
  } catch {}
193
181
  },
194
- async getAccount() {
195
- return (await readAccountState(provider, info.name))?.account ?? null;
182
+ getAccounts: () => readAccounts(provider),
183
+ async getBalance(options) {
184
+ return readEvmBalance(provider, await resolveAddress(options?.account), options?.token);
196
185
  },
197
- async getAccounts() {
198
- return (await readAccountState(provider, info.name))?.accounts ?? [];
199
- },
200
- async getBalance(mint) {
201
- const first = (await requestStringArray(provider, { method: "eth_accounts" }))[0];
202
- if (first === void 0) throw new Error("No connected account");
203
- return readEvmBalance(provider, first, mint);
204
- },
205
- getSigner: () => Promise.resolve(provider),
206
- async getTransactionReceipt(tx) {
186
+ getSigner: () => Promise.resolve({
187
+ kind: "eip1193",
188
+ provider
189
+ }),
190
+ async getTransactionReceipt(hash) {
207
191
  const receipt = await provider.request({
208
192
  method: "eth_getTransactionReceipt",
209
- params: [tx]
193
+ params: [hash]
210
194
  });
211
195
  if (receipt === null || typeof receipt !== "object" || !("status" in receipt)) return { status: "Pending" };
212
196
  return { status: receipt.status === "0x1" ? "Success" : "Error" };
@@ -221,86 +205,66 @@ const buildEvmAdapter = (info, provider) => {
221
205
  params: [{ eth_accounts: {} }]
222
206
  });
223
207
  } catch (error) {
224
- const outerCode = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
225
- const errData = typeof error === "object" && error !== null && "data" in error ? error.data : void 0;
226
- const originalError = typeof errData === "object" && errData !== null && "originalError" in errData ? errData.originalError : void 0;
227
- const innerCode = typeof originalError === "object" && originalError !== null && "code" in originalError ? originalError.code : void 0;
228
- if (outerCode === 4200 || outerCode === -32601 || outerCode === -32603 || innerCode === 4200 || innerCode === -32601 || innerCode === -32604) {
229
- await provider.request({ method: "eth_requestAccounts" });
230
- return;
231
- }
232
- throw error;
208
+ const outer = typeof error === "object" && error !== null ? error : {};
209
+ const data = "data" in outer ? outer.data : void 0;
210
+ const inner = typeof data === "object" && data !== null && "originalError" in data ? data.originalError : void 0;
211
+ if (!("code" in outer && METHOD_NOT_SUPPORTED_CODES.has(outer.code) || typeof inner === "object" && inner !== null && "code" in inner && METHOD_NOT_SUPPORTED_CODES.has(inner.code))) throw error;
212
+ await provider.request({ method: "eth_requestAccounts" });
233
213
  }
234
214
  },
235
- async sendTx(tx, account) {
236
- const txWithFrom = withFrom(tx, account?.walletAddress);
237
- const hash = await requestString(provider, {
238
- method: "eth_sendTransaction",
239
- params: [txWithFrom]
240
- });
241
- if (hash === null) throw new Error("Wallet returned no transaction hash");
242
- return hash;
243
- },
244
- async sendTxToChain(tx, targetChainIdDecimal, account, cb) {
245
- const current = await requestString(provider, { method: "eth_chainId" });
246
- const targetHex = chainIdDecimalToHex(targetChainIdDecimal);
247
- if (current?.toLowerCase() !== targetHex.toLowerCase()) {
248
- await provider.request({
249
- method: "wallet_switchEthereumChain",
250
- params: [{ chainId: targetHex }]
251
- });
252
- cb?.();
253
- }
254
- const txWithFrom = withFrom(tx, account?.walletAddress);
215
+ async sendTx(tx, options) {
216
+ const from = await resolveAddress(options?.account);
217
+ if (options?.chain !== void 0) await switchChain(options.chain);
255
218
  const hash = await requestString(provider, {
256
219
  method: "eth_sendTransaction",
257
- params: [txWithFrom]
220
+ params: [encodeValue({
221
+ ...tx,
222
+ from
223
+ })]
258
224
  });
259
225
  if (hash === null) throw new Error("Wallet returned no transaction hash");
260
226
  return hash;
261
227
  },
262
- async signMessage(msg, account) {
263
- let signer = account?.walletAddress;
264
- if (signer === void 0 || signer === "") signer = (await requestStringArray(provider, { method: "eth_accounts" }))[0];
265
- if (signer === void 0 || signer === "") throw new Error("No connected account");
228
+ async signMessage(message, options) {
229
+ const address = await resolveAddress(options?.account);
266
230
  const signatureHex = await requestString(provider, {
267
231
  method: "personal_sign",
268
- params: [bytesToHexPrefixed(msg), signer]
232
+ params: [bytesToHexPrefixed(message), address]
269
233
  });
270
234
  if (signatureHex === null) throw new Error("Wallet returned a malformed personal_sign response");
271
235
  return {
272
- signature: hexToBytes$1(signatureHex),
273
- signedMessage: msg
236
+ signature: hexToBytes(signatureHex),
237
+ signedMessage: message
274
238
  };
275
239
  },
276
240
  subscribe(listener) {
277
- const synchronizeAccount = async (options) => {
241
+ const synchronize = async (known) => {
278
242
  try {
279
- const state = await readAccountState(provider, info.name, options);
280
- if (state !== null) listener({
281
- ...state,
282
- type: "accountChanged"
243
+ const accounts = await readAccounts(provider, known);
244
+ if (accounts.length > 0) listener({
245
+ accounts,
246
+ type: "accountsChanged"
283
247
  });
284
248
  } catch {}
285
249
  };
286
250
  const onAccountsChanged = (...args) => {
287
- const accs = toStringArray(args[0]);
288
- if (accs.length === 0) {
251
+ const addresses = toStringArray(args[0]);
252
+ if (addresses.length === 0) {
289
253
  listener({ type: "disconnected" });
290
254
  return;
291
255
  }
292
- synchronizeAccount({ accounts: accs });
256
+ synchronize({ addresses });
293
257
  };
294
258
  const onChainChanged = (...args) => {
295
259
  const [chainId] = args;
296
260
  const chainIdHex = typeof chainId === "string" && chainId.length > 0 ? chainId : void 0;
297
- synchronizeAccount({ chainIdHex });
261
+ synchronize({ chainIdHex });
298
262
  };
299
263
  const onDisconnect = () => {
300
264
  listener({ type: "disconnected" });
301
265
  };
302
266
  const onConnect = () => {
303
- synchronizeAccount();
267
+ synchronize();
304
268
  };
305
269
  provider.on("accountsChanged", onAccountsChanged);
306
270
  provider.on("chainChanged", onChainChanged);
@@ -313,14 +277,7 @@ const buildEvmAdapter = (info, provider) => {
313
277
  provider.removeListener("disconnect", onDisconnect);
314
278
  };
315
279
  },
316
- async switchChain(chain) {
317
- const targetHex = chainIdDecimalToHex(chain.reference);
318
- if ((await requestString(provider, { method: "eth_chainId" }))?.toLowerCase() === targetHex.toLowerCase()) return;
319
- await provider.request({
320
- method: "wallet_switchEthereumChain",
321
- params: [{ chainId: targetHex }]
322
- });
323
- }
280
+ switchChain
324
281
  };
325
282
  };
326
283
 
@@ -336,9 +293,10 @@ const isEip6963AnnounceEvent = (event) => {
336
293
  const { info, provider } = detail;
337
294
  return typeof info === "object" && info !== null && "icon" in info && typeof info.icon === "string" && "name" in info && typeof info.name === "string" && "rdns" in info && typeof info.rdns === "string" && "uuid" in info && typeof info.uuid === "string" && typeof provider === "object" && provider !== null && "on" in provider && typeof provider.on === "function" && "removeListener" in provider && typeof provider.removeListener === "function" && "request" in provider && typeof provider.request === "function";
338
295
  };
296
+ const windowGlobal = globalThis;
339
297
  const resolveTarget = (target) => {
340
298
  if (target !== void 0) return target;
341
- return globalThis.window ?? null;
299
+ return windowGlobal.window ?? null;
342
300
  };
343
301
  /**
344
302
  * Spec: https://eips.ethereum.org/EIPS/eip-6963. Dedupe is by `info.rdns`
@@ -373,7 +331,10 @@ const discoverEvmAdapters = (onAdapter, options = {}) => {
373
331
  */
374
332
  const GENERIC_INJECTED_ICON = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMjEgMTJWN0g1YTIgMiAwIDAgMSAwLTQgaDE0djQiLz48cGF0aCBkPSJNMyA1djE0YTIgMiAwIDAgMCAyIDJoMTZ2LTVNMjEgMTIgaC0zYTIgMiAwIDAgMC0yIDJ2MGEyIDIgMCAwIDAgMiAyaDN6Ii8+PC9zdmc+";
375
333
  const DEFAULT_SETTLE_MS = 150;
376
- const isEip1193Provider = (value) => value !== void 0 && "on" in value && typeof value.on === "function" && "removeListener" in value && typeof value.removeListener === "function" && "request" in value && typeof value.request === "function";
334
+ /** Structural check for code that holds a provider of unknown origin, such
335
+ * as `window.ethereum`. A butr signer narrows on `kind === "eip1193"`
336
+ * instead. */
337
+ const isEip1193Provider = (value) => typeof value === "object" && value !== null && "on" in value && typeof value.on === "function" && "removeListener" in value && typeof value.removeListener === "function" && "request" in value && typeof value.request === "function";
377
338
  const readEthereum = (target) => {
378
339
  const host = target === void 0 ? globalThis.window : target;
379
340
  return isEip1193Provider(host?.ethereum) ? host.ethereum : null;
@@ -404,59 +365,6 @@ const discoverInjectedAdapter = (onAdapter, options = {}) => {
404
365
  };
405
366
  };
406
367
 
407
- //#endregion
408
- //#region src/chains.ts
409
- /**
410
- * Common EVM chain registry keyed by CAIP-2 id. Useful for chain-
411
- * switcher UIs. butr itself doesn't read this: `Connector.switchChain`
412
- * accepts any `ChainBase`.
413
- */
414
- const EVM_CHAINS = {
415
- arbitrum: {
416
- id: "eip155:42161",
417
- name: "Arbitrum One",
418
- namespace: "eip155",
419
- reference: "42161"
420
- },
421
- base: {
422
- id: "eip155:8453",
423
- name: "Base",
424
- namespace: "eip155",
425
- reference: "8453"
426
- },
427
- bsc: {
428
- id: "eip155:56",
429
- name: "BNB Smart Chain",
430
- namespace: "eip155",
431
- reference: "56"
432
- },
433
- ethereum: {
434
- id: "eip155:1",
435
- name: "Ethereum",
436
- namespace: "eip155",
437
- reference: "1"
438
- },
439
- optimism: {
440
- id: "eip155:10",
441
- name: "Optimism",
442
- namespace: "eip155",
443
- reference: "10"
444
- },
445
- polygon: {
446
- id: "eip155:137",
447
- name: "Polygon",
448
- namespace: "eip155",
449
- reference: "137"
450
- },
451
- sepolia: {
452
- id: "eip155:11155111",
453
- name: "Sepolia",
454
- namespace: "eip155",
455
- reference: "11155111"
456
- }
457
- };
458
- const EVM_CHAINS_LIST = Object.values(EVM_CHAINS);
459
-
460
368
  //#endregion
461
369
  //#region src/discoverer.ts
462
370
  /**
@@ -469,5 +377,5 @@ const evmDiscoverer = {
469
377
  };
470
378
 
471
379
  //#endregion
472
- export { ANNOUNCE_EVENT, EIP6963_RDNS_WITH_REQUEST_ACCOUNTS, EVM_CHAINS, EVM_CHAINS_LIST, GENERIC_INJECTED_ICON, REQUEST_EVENT, buildEvmAdapter, bytesToHex, chainIdDecimalToHex, chainIdHexToDecimal, discoverEvmAdapters, discoverInjectedAdapter, evmDiscoverer, formatEther, hexToBytes, isEip1193Provider, resolveEip6963Capabilities };
380
+ export { ANNOUNCE_EVENT, GENERIC_INJECTED_ICON, REQUEST_EVENT, buildEvmAdapter, chainIdDecimalToHex, chainIdHexToDecimal, discoverEvmAdapters, discoverInjectedAdapter, evmDiscoverer, formatEther, isEip1193Provider };
473
381
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["HEX_PREFIX","hexToBytes","bytesToHex","hexToBytes"],"sources":["../src/capabilities.ts","../src/eip1193.ts","../src/evm-balance.ts","../src/eip6963-adapter.ts","../src/eip6963.ts","../src/injected.ts","../src/chains.ts","../src/discoverer.ts"],"sourcesContent":["import type { WalletCapabilities } from \"@usebutr/core\";\n\nconst EIP6963_RDNS_WITH_REQUEST_ACCOUNTS = new Set<string>([\n \"io.metamask\", // MetaMask: verified May 2026\n]);\n\ntype Eip6963CapabilityInput = { rdns: string };\n\nconst resolveEip6963Capabilities = (input: Eip6963CapabilityInput): WalletCapabilities => ({\n getBalance: true,\n getTransactionReceipt: true,\n requestAccounts: EIP6963_RDNS_WITH_REQUEST_ACCOUNTS.has(input.rdns),\n sendTransaction: true,\n signIn: false,\n signMessage: true,\n signTransaction: false,\n subscribe: true,\n switchAccount: false,\n switchChain: true,\n});\n\nexport type { Eip6963CapabilityInput };\nexport { EIP6963_RDNS_WITH_REQUEST_ACCOUNTS, resolveEip6963Capabilities };\n","/**\n * Declared inline rather than taken from `viem`, which would expand butr's\n * footprint. Loose on purpose: `request(...)` returns `unknown` and the\n * `request*` helpers narrow it at the boundary.\n */\n\ntype Eip1193Object = { [key: string]: Eip1193Value | undefined };\ntype Eip1193Value =\n | bigint\n | boolean\n | number\n | string\n | null\n | Uint8Array\n | ReadonlyArray<Eip1193Value>\n | Eip1193Object;\n\ntype Eip1193RequestArgs = {\n method: string;\n params?: ReadonlyArray<Eip1193Value> | Eip1193Object;\n};\n\ntype Eip1193Listener = (...args: ReadonlyArray<Eip1193Value | undefined>) => void;\n\ntype Eip1193Provider = {\n on: (event: string, listener: Eip1193Listener) => void;\n removeListener: (event: string, listener: Eip1193Listener) => void;\n request: (args: Eip1193RequestArgs) => Promise<Eip1193Value | undefined>;\n};\n\ntype Eip6963ProviderInfo = {\n /** Data URI or absolute URL pointing at the wallet's icon. */\n icon: string;\n /** Human-readable wallet name shown in pickers. */\n name: string;\n /** Reverse-DNS identifier: `io.metamask`, `io.rabby`, `app.phantom`.\n * Stable across versions, unique per wallet, used as the pool key. */\n rdns: string;\n /** Per-page UUID generated by the wallet. Not stable across reloads. */\n uuid: string;\n};\n\ntype Eip6963ProviderDetail = {\n info: Eip6963ProviderInfo;\n provider: Eip1193Provider;\n};\n\ntype Eip6963AnnounceEvent = CustomEvent<Eip6963ProviderDetail>;\n\n/** `provider.request` is typed `unknown` by design; these helpers narrow\n * the well-known EVM RPC shapes at the boundary with runtime guards so\n * call sites stay assertion-free. A malformed response is reported as\n * `null` / `[]` rather than a blank value, so call sites that cannot\n * proceed without a real one fail instead of inventing a default. */\nconst requestString = async (\n provider: Eip1193Provider,\n args: Eip1193RequestArgs,\n): Promise<string | null> => {\n const result = await provider.request(args);\n return typeof result === \"string\" ? result : null;\n};\n\nconst requestStringArray = async (\n provider: Eip1193Provider,\n args: Eip1193RequestArgs,\n): Promise<Array<string>> => {\n const result = await provider.request(args);\n return Array.isArray(result)\n ? result.filter((item): item is string => typeof item === \"string\")\n : [];\n};\n\nexport { requestString, requestStringArray };\n\nexport type {\n Eip1193Listener,\n Eip1193Object,\n Eip1193Provider,\n Eip1193RequestArgs,\n Eip1193Value,\n Eip6963AnnounceEvent,\n Eip6963ProviderDetail,\n Eip6963ProviderInfo,\n};\n","import { hexToBytes } from \"@usebutr/core\";\n\nimport type { Eip1193Provider } from \"./eip1193\";\nimport { requestString } from \"./eip1193\";\n\nconst HEX_PREFIX = \"0x\";\nconst ETH_DECIMALS = 18n;\nconst ERC20_BALANCE_OF_SELECTOR = \"0x70a08231\";\nconst ERC20_DECIMALS_SELECTOR = \"0x313ce567\";\nconst ERC20_SYMBOL_SELECTOR = \"0x95d89b41\";\n\n/** A failed read must not render as a confident zero balance. */\nconst requireHex = (hex: string | null, label: string): string => {\n if (hex === null) {\n throw new Error(`Wallet returned a malformed ${label} response`);\n }\n return hex;\n};\n\nconst formatUnits = (raw: bigint, decimals: number): string => {\n if (decimals === 0) {\n return raw.toString();\n }\n const unit = 10n ** BigInt(decimals);\n const integer = raw / unit;\n const remainder = raw % unit;\n if (remainder === 0n) {\n return integer.toString();\n }\n const fraction = remainder.toString().padStart(decimals, \"0\").replace(/0+$/v, \"\");\n return `${integer}.${fraction}`;\n};\n\nconst formatEther = (wei: bigint): string => formatUnits(wei, Number(ETH_DECIMALS));\n\nconst padAddressForCall = (address: string): string =>\n address.replace(/^0x/v, \"\").toLowerCase().padStart(64, \"0\");\n\nconst decodeAbiString = (hex: string): string => {\n const clean = hex.startsWith(HEX_PREFIX) ? hex.slice(2) : hex;\n if (clean.length === 0) {\n return \"\";\n }\n if (clean.length >= 128) {\n const lengthHex = clean.slice(64, 128);\n const length = Number(BigInt(`0x${lengthHex}`));\n if (length > 0 && clean.length >= 128 + length * 2) {\n return new TextDecoder().decode(hexToBytes(clean.slice(128, 128 + length * 2)));\n }\n }\n const bytes = hexToBytes(clean.slice(0, 64));\n let end = bytes.length;\n while (end > 0 && bytes[end - 1] === 0) {\n end -= 1;\n }\n return new TextDecoder().decode(bytes.subarray(0, end));\n};\n\nconst readEvmBalance = async (\n provider: Eip1193Provider,\n address: string,\n tokenAddress?: string,\n) => {\n if (tokenAddress === undefined || tokenAddress === \"\") {\n const balanceHex = await requestString(provider, {\n method: \"eth_getBalance\",\n params: [address, \"latest\"],\n });\n const value = BigInt(requireHex(balanceHex, \"eth_getBalance\"));\n return {\n decimals: Number(ETH_DECIMALS),\n formatted: formatEther(value),\n symbol: \"ETH\",\n value,\n };\n }\n\n const [balanceHex, decimalsHex, symbolHex] = await Promise.all([\n requestString(provider, {\n method: \"eth_call\",\n params: [\n { data: `${ERC20_BALANCE_OF_SELECTOR}${padAddressForCall(address)}`, to: tokenAddress },\n \"latest\",\n ],\n }),\n requestString(provider, {\n method: \"eth_call\",\n params: [{ data: ERC20_DECIMALS_SELECTOR, to: tokenAddress }, \"latest\"],\n }),\n requestString(provider, {\n method: \"eth_call\",\n params: [{ data: ERC20_SYMBOL_SELECTOR, to: tokenAddress }, \"latest\"],\n }),\n ]);\n const value = BigInt(requireHex(balanceHex, \"balanceOf()\"));\n const decimals = Number(BigInt(requireHex(decimalsHex, \"decimals()\")));\n return {\n decimals,\n formatted: formatUnits(value, decimals),\n symbol: decodeAbiString(symbolHex ?? \"\"),\n value,\n };\n};\n\nexport { formatEther, readEvmBalance };\n","import type {\n Account,\n ChainBase,\n TransactionInput,\n TransactionValue,\n WalletAdapter,\n} from \"@usebutr/core\";\nimport { bytesToHexPrefixed as bytesToHex, hexToBytes, sanitizeIcon } from \"@usebutr/core\";\n\nimport { resolveEip6963Capabilities } from \"./capabilities\";\nimport type {\n Eip1193Listener,\n Eip1193Object,\n Eip1193Provider,\n Eip1193Value,\n Eip6963ProviderInfo,\n} from \"./eip1193\";\nimport { requestString, requestStringArray } from \"./eip1193\";\nimport { readEvmBalance } from \"./evm-balance\";\n\nconst HEX_PREFIX = \"0x\";\n\nconst toStringArray = (value: Eip1193Value | undefined): Array<string> =>\n Array.isArray(value) ? value.filter((item): item is string => typeof item === \"string\") : [];\n\nconst toEip1193Value = (value: TransactionValue): Eip1193Value => {\n if (typeof value === \"function\") {\n throw new TypeError(\"EVM transactions cannot contain functions\");\n }\n if (Array.isArray(value)) {\n return value.map(toEip1193Value);\n }\n if (value instanceof Uint8Array) {\n return value;\n }\n if (typeof value === \"object\" && value !== null) {\n const result: Eip1193Object = {};\n for (const [key, nested] of Object.entries(value)) {\n result[key] = nested === undefined ? undefined : toEip1193Value(nested);\n }\n return result;\n }\n return value;\n};\n\nconst withFrom = (tx: TransactionInput, from?: string): Eip1193Value => {\n if (typeof tx === \"string\" || tx instanceof Uint8Array) {\n return tx;\n }\n const result: Eip1193Object = {};\n for (const [key, value] of Object.entries(tx)) {\n result[key] = value === undefined ? undefined : toEip1193Value(value);\n }\n if (from !== undefined) {\n result.from = from;\n }\n return result;\n};\n\nconst chainIdHexToDecimal = (hex: string): string => BigInt(hex).toString(10);\nconst chainIdDecimalToHex = (dec: string): string => `${HEX_PREFIX}${BigInt(dec).toString(16)}`;\n\nconst buildEvmChain = (chainIdHex: string, walletName: string): ChainBase => {\n const reference = chainIdHexToDecimal(chainIdHex);\n return {\n id: `eip155:${reference}`,\n name: walletName,\n namespace: \"eip155\",\n reference,\n };\n};\n\nconst buildEvmAccount = (address: string, chain: ChainBase): Account => ({\n chain,\n id: `${chain.id}:${address.toLowerCase()}`,\n walletAddress: address,\n});\n\ntype AccountStateOptions = {\n accounts?: Array<string>;\n chainIdHex?: string;\n};\n\n/** Rejections propagate: `getAccount`/`getAccounts` surface the wallet's\n * own provider error, while the `subscribe` bridge swallows it because a\n * later event retries synchronization. */\nconst readAccountState = async (\n provider: Eip1193Provider,\n walletName: string,\n options: AccountStateOptions = {},\n) => {\n const accounts =\n options.accounts ?? (await requestStringArray(provider, { method: \"eth_accounts\" }));\n if (accounts.length === 0) {\n return null;\n }\n const chainIdHex =\n options.chainIdHex ?? (await requestString(provider, { method: \"eth_chainId\" }));\n if (chainIdHex === null) {\n throw new Error(\"Wallet returned a malformed eth_chainId response\");\n }\n const chain = buildEvmChain(chainIdHex, walletName);\n const builtAccounts = accounts.map((address) => buildEvmAccount(address, chain));\n const account = builtAccounts[0];\n return account === undefined ? null : { account, accounts: builtAccounts };\n};\n\n/**\n * `disconnect` calls `wallet_revokePermissions`, which many wallets don't\n * implement and silently ignore, so their own auto-reconnect may outlive it.\n * `getBalance()` labels the native balance `\"ETH\"` on every EVM chain.\n */\nconst buildEvmAdapter = (info: Eip6963ProviderInfo, provider: Eip1193Provider): WalletAdapter => {\n return {\n capabilities: resolveEip6963Capabilities({ rdns: info.rdns }),\n chainPlatform: \"evm\",\n\n async connect(opts) {\n if (opts?.silent === true) {\n const accounts = await requestStringArray(provider, {\n method: \"eth_accounts\",\n });\n if (accounts.length === 0) {\n throw new Error(\"No authorized accounts for silent reconnect\");\n }\n return;\n }\n await provider.request({ method: \"eth_requestAccounts\" });\n },\n\n async disconnect() {\n try {\n await provider.request({\n method: \"wallet_revokePermissions\",\n params: [{ eth_accounts: {} }],\n });\n } catch {\n // Many wallets don't implement wallet_revokePermissions yet;\n // not a failure.\n }\n },\n\n async getAccount() {\n const state = await readAccountState(provider, info.name);\n return state?.account ?? null;\n },\n\n async getAccounts() {\n const state = await readAccountState(provider, info.name);\n return state?.accounts ?? [];\n },\n\n async getBalance(mint) {\n const accounts = await requestStringArray(provider, { method: \"eth_accounts\" });\n const first = accounts[0];\n if (first === undefined) {\n throw new Error(\"No connected account\");\n }\n return readEvmBalance(provider, first, mint);\n },\n\n getSigner: () => Promise.resolve(provider),\n\n async getTransactionReceipt(tx) {\n const receipt = await provider.request({\n method: \"eth_getTransactionReceipt\",\n params: [tx],\n });\n if (receipt === null || typeof receipt !== \"object\" || !(\"status\" in receipt)) {\n return { status: \"Pending\" };\n }\n return { status: receipt.status === \"0x1\" ? \"Success\" : \"Error\" };\n },\n\n icon: sanitizeIcon(info.icon),\n id: info.rdns,\n name: info.name,\n\n async requestAccounts() {\n try {\n await provider.request({\n method: \"wallet_requestPermissions\",\n params: [{ eth_accounts: {} }],\n });\n } catch (error) {\n const outerCode =\n typeof error === \"object\" && error !== null && \"code\" in error ? error.code : undefined;\n const errData =\n typeof error === \"object\" && error !== null && \"data\" in error ? error.data : undefined;\n const originalError =\n typeof errData === \"object\" && errData !== null && \"originalError\" in errData\n ? errData.originalError\n : undefined;\n const innerCode =\n typeof originalError === \"object\" && originalError !== null && \"code\" in originalError\n ? originalError.code\n : undefined;\n const isMethodNotSupported =\n outerCode === 4200 || // EIP-1474 \"method not supported\"\n outerCode === -32_601 || // JSON-RPC \"method not found\"\n outerCode === -32_603 || // JSON-RPC \"internal error\" (Coinbase wraps -32604 here)\n innerCode === 4200 ||\n innerCode === -32_601 ||\n innerCode === -32_604; // Coinbase's custom \"method not supported\"\n if (isMethodNotSupported) {\n await provider.request({ method: \"eth_requestAccounts\" });\n return;\n }\n throw error;\n }\n },\n\n async sendTx(tx, account) {\n const txWithFrom = withFrom(tx, account?.walletAddress);\n const hash = await requestString(provider, {\n method: \"eth_sendTransaction\",\n params: [txWithFrom],\n });\n if (hash === null) {\n throw new Error(\"Wallet returned no transaction hash\");\n }\n return hash;\n },\n\n async sendTxToChain(tx, targetChainIdDecimal, account, cb) {\n const current = await requestString(provider, { method: \"eth_chainId\" });\n const targetHex = chainIdDecimalToHex(targetChainIdDecimal);\n if (current?.toLowerCase() !== targetHex.toLowerCase()) {\n await provider.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: targetHex }],\n });\n cb?.();\n }\n const txWithFrom = withFrom(tx, account?.walletAddress);\n const hash = await requestString(provider, {\n method: \"eth_sendTransaction\",\n params: [txWithFrom],\n });\n if (hash === null) {\n throw new Error(\"Wallet returned no transaction hash\");\n }\n return hash;\n },\n\n async signMessage(msg, account) {\n let signer = account?.walletAddress;\n if (signer === undefined || signer === \"\") {\n const accounts = await requestStringArray(provider, { method: \"eth_accounts\" });\n signer = accounts[0];\n }\n if (signer === undefined || signer === \"\") {\n throw new Error(\"No connected account\");\n }\n const signatureHex = await requestString(provider, {\n method: \"personal_sign\",\n params: [bytesToHex(msg), signer],\n });\n if (signatureHex === null) {\n throw new Error(\"Wallet returned a malformed personal_sign response\");\n }\n return { signature: hexToBytes(signatureHex), signedMessage: msg };\n },\n\n subscribe(listener) {\n const synchronizeAccount = async (options?: AccountStateOptions) => {\n try {\n const state = await readAccountState(provider, info.name, options);\n if (state !== null) {\n listener({ ...state, type: \"accountChanged\" });\n }\n } catch {\n // EIP-1193 event reads are best-effort; a later event retries synchronization.\n }\n };\n\n const onAccountsChanged: Eip1193Listener = (...args) => {\n const accs = toStringArray(args[0]);\n if (accs.length === 0) {\n listener({ type: \"disconnected\" });\n return;\n }\n void synchronizeAccount({ accounts: accs });\n };\n\n const onChainChanged: Eip1193Listener = (...args) => {\n const [chainId] = args;\n // Some wallets emit a decimal number here instead of the EIP-1193\n // hex string; leaving it absent re-engages the eth_chainId read.\n const chainIdHex = typeof chainId === \"string\" && chainId.length > 0 ? chainId : undefined;\n void synchronizeAccount({ chainIdHex });\n };\n\n const onDisconnect: Eip1193Listener = () => {\n listener({ type: \"disconnected\" });\n };\n\n const onConnect: Eip1193Listener = () => {\n void synchronizeAccount();\n };\n\n provider.on(\"accountsChanged\", onAccountsChanged);\n provider.on(\"chainChanged\", onChainChanged);\n provider.on(\"connect\", onConnect);\n provider.on(\"disconnect\", onDisconnect);\n\n return () => {\n provider.removeListener(\"accountsChanged\", onAccountsChanged);\n provider.removeListener(\"chainChanged\", onChainChanged);\n provider.removeListener(\"connect\", onConnect);\n provider.removeListener(\"disconnect\", onDisconnect);\n };\n },\n\n async switchChain(chain) {\n const targetHex = chainIdDecimalToHex(chain.reference);\n const current = await requestString(provider, { method: \"eth_chainId\" });\n if (current?.toLowerCase() === targetHex.toLowerCase()) {\n return;\n }\n await provider.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: targetHex }],\n });\n },\n };\n};\n\nexport { bytesToHexPrefixed as bytesToHex, hexToBytes } from \"@usebutr/core\";\nexport { formatEther } from \"./evm-balance\";\nexport { buildEvmAdapter, chainIdDecimalToHex, chainIdHexToDecimal };\n","import type { WalletAdapter } from \"@usebutr/core\";\n\nimport type { Eip6963AnnounceEvent, Eip6963ProviderInfo } from \"./eip1193\";\nimport { buildEvmAdapter } from \"./eip6963-adapter\";\n\nconst ANNOUNCE_EVENT = \"eip6963:announceProvider\";\nconst REQUEST_EVENT = \"eip6963:requestProvider\";\n\ntype AdapterCallback = (adapter: WalletAdapter, info: Eip6963ProviderInfo) => void;\n\ntype DiscoverOptions = {\n /** Event target to listen on. Defaults to `window` in browser/RN/\n * SSR'd environments; tests can pass a fresh `new EventTarget()` to\n * exercise the discovery loop without a DOM. */\n target?: EventTarget;\n};\n\nconst isEip6963AnnounceEvent = (event: Event): event is Eip6963AnnounceEvent => {\n if (!(\"detail\" in event)) {\n return false;\n }\n const detail: unknown = event.detail;\n if (typeof detail !== \"object\" || detail === null) {\n return false;\n }\n if (!(\"info\" in detail) || !(\"provider\" in detail)) {\n return false;\n }\n const { info, provider } = detail;\n return (\n typeof info === \"object\" &&\n info !== null &&\n \"icon\" in info &&\n typeof info.icon === \"string\" &&\n \"name\" in info &&\n typeof info.name === \"string\" &&\n \"rdns\" in info &&\n typeof info.rdns === \"string\" &&\n \"uuid\" in info &&\n typeof info.uuid === \"string\" &&\n typeof provider === \"object\" &&\n provider !== null &&\n \"on\" in provider &&\n typeof provider.on === \"function\" &&\n \"removeListener\" in provider &&\n typeof provider.removeListener === \"function\" &&\n \"request\" in provider &&\n typeof provider.request === \"function\"\n );\n};\n\nconst resolveTarget = (target?: EventTarget): EventTarget | null => {\n if (target !== undefined) {\n return target;\n }\n return globalThis.window ?? null;\n};\n\n/**\n * Spec: https://eips.ethereum.org/EIPS/eip-6963. Dedupe is by `info.rdns`\n * because `info.uuid` is regenerated per page load. The listener stays\n * attached for the session so wallets that boot late still register.\n */\nconst discoverEvmAdapters = (\n onAdapter: AdapterCallback,\n options: DiscoverOptions = {},\n): (() => void) => {\n const target = resolveTarget(options.target);\n if (!target) {\n return () => {};\n }\n\n const seen = new Set<string>();\n const handler = (event: Event) => {\n if (!isEip6963AnnounceEvent(event)) {\n return;\n }\n const { info, provider } = event.detail;\n if (info.rdns.length === 0) {\n return;\n }\n if (seen.has(info.rdns)) {\n return;\n }\n seen.add(info.rdns);\n onAdapter(buildEvmAdapter(info, provider), info);\n };\n\n target.addEventListener(ANNOUNCE_EVENT, handler);\n target.dispatchEvent(new Event(REQUEST_EVENT));\n\n return () => {\n target.removeEventListener(ANNOUNCE_EVENT, handler);\n };\n};\n\nexport { ANNOUNCE_EVENT, REQUEST_EVENT, discoverEvmAdapters };\n","import type { WalletAdapter, WalletSigner } from \"@usebutr/core\";\n\nimport type { Eip1193Provider, Eip6963ProviderInfo } from \"./eip1193\";\nimport { buildEvmAdapter } from \"./eip6963-adapter\";\n\n/**\n * Generic wallet icon (a stylised purse SVG, ~600 bytes). Used as\n * the fallback icon when an injected provider has no EIP-6963 info.\n * Inline rather than a network fetch so the picker doesn't flicker.\n */\nconst GENERIC_INJECTED_ICON =\n \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMjEgMTJWN0g1YTIgMiAwIDAgMSAwLTQgaDE0djQiLz48cGF0aCBkPSJNMyA1djE0YTIgMiAwIDAgMCAyIDJoMTZ2LTVNMjEgMTIgaC0zYTIgMiAwIDAgMC0yIDJ2MGEyIDIgMCAwIDAgMiAyaDN6Ii8+PC9zdmc+\";\n\nconst DEFAULT_SETTLE_MS = 150;\n\ntype InjectedDiscoveryOptions = {\n /**\n * Consulted before emitting: an already-registered EIP-6963 adapter means\n * the wallet is covered by the standards path and emitting would duplicate\n * it. Omit to always emit.\n */\n hasAnyEip6963Adapter?: () => boolean;\n /**\n * Most wallets announce within the first frame; 150ms leaves room for slow\n * announcements without stalling the picker.\n */\n settleMs?: number;\n /** Override the global `window` reference (tests, iframes). */\n target?: { ethereum?: Partial<Eip1193Provider> } | null;\n};\n\ndeclare global {\n // oxlint-disable-next-line typescript/consistent-type-definitions -- DOM globals require interface merging.\n interface Window {\n ethereum?: Partial<Eip1193Provider>;\n }\n}\n\nconst isEip1193Provider = (value: WalletSigner | undefined): value is Eip1193Provider =>\n value !== undefined &&\n \"on\" in value &&\n typeof value.on === \"function\" &&\n \"removeListener\" in value &&\n typeof value.removeListener === \"function\" &&\n \"request\" in value &&\n typeof value.request === \"function\";\n\nconst readEthereum = (target: InjectedDiscoveryOptions[\"target\"]): Eip1193Provider | null => {\n const host = target === undefined ? globalThis.window : target;\n return isEip1193Provider(host?.ethereum) ? host.ethereum : null;\n};\n\n/**\n * Last-resort path for the long tail of EVM wallets that expose only\n * `window.ethereum` and never announce via EIP-6963. The emitted adapter\n * carries `rdns: \"injected:legacy\"` so consumers can tell it apart.\n */\nconst discoverInjectedAdapter = (\n onAdapter: (adapter: WalletAdapter) => void,\n options: InjectedDiscoveryOptions = {},\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.hasAnyEip6963Adapter?.() === true) {\n return;\n }\n const provider = readEthereum(options.target);\n if (provider === null) {\n return;\n }\n const info: Eip6963ProviderInfo = {\n icon: GENERIC_INJECTED_ICON,\n name: \"Browser wallet\",\n rdns: \"injected:legacy\",\n uuid: \"injected:legacy\",\n };\n onAdapter(buildEvmAdapter(info, provider));\n }, settleMs);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n};\n\nexport type { InjectedDiscoveryOptions };\nexport { GENERIC_INJECTED_ICON, discoverInjectedAdapter, isEip1193Provider };\n","import type { ChainBase } from \"@usebutr/core\";\n\n/**\n * Common EVM chain registry keyed by CAIP-2 id. Useful for chain-\n * switcher UIs. butr itself doesn't read this: `Connector.switchChain`\n * accepts any `ChainBase`.\n */\nconst EVM_CHAINS = {\n arbitrum: {\n id: \"eip155:42161\",\n name: \"Arbitrum One\",\n namespace: \"eip155\",\n reference: \"42161\",\n },\n base: { id: \"eip155:8453\", name: \"Base\", namespace: \"eip155\", reference: \"8453\" },\n bsc: { id: \"eip155:56\", name: \"BNB Smart Chain\", namespace: \"eip155\", reference: \"56\" },\n ethereum: { id: \"eip155:1\", name: \"Ethereum\", namespace: \"eip155\", reference: \"1\" },\n optimism: { id: \"eip155:10\", name: \"Optimism\", namespace: \"eip155\", reference: \"10\" },\n polygon: { id: \"eip155:137\", name: \"Polygon\", namespace: \"eip155\", reference: \"137\" },\n sepolia: { id: \"eip155:11155111\", name: \"Sepolia\", namespace: \"eip155\", reference: \"11155111\" },\n} as const satisfies Record<string, ChainBase>;\n\nconst EVM_CHAINS_LIST: ReadonlyArray<ChainBase> = Object.values(EVM_CHAINS);\n\nexport { EVM_CHAINS, EVM_CHAINS_LIST };\n","import type { PlatformDiscoverer } from \"@usebutr/core\";\n\nimport { discoverEvmAdapters } from \"./eip6963\";\nimport { discoverInjectedAdapter } from \"./injected\";\n\n/**\n * EIP-6963 is primary; the legacy `window.ethereum` fallback defers until\n * EIP-6963 has had a chance to fire.\n */\nconst evmDiscoverer: PlatformDiscoverer = {\n fallback: {\n subscribe: (onAdapter, opts) =>\n discoverInjectedAdapter(onAdapter, {\n hasAnyEip6963Adapter: opts.hasAnyPrimaryAdapter,\n }),\n },\n subscribe: discoverEvmAdapters,\n};\n\nexport { evmDiscoverer };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/eip1193.ts","../src/evm-balance.ts","../src/eip6963-adapter.ts","../src/eip6963.ts","../src/injected.ts","../src/discoverer.ts"],"sourcesContent":["/**\n * Declared inline rather than taken from `viem`, which would expand butr's\n * footprint. Loose on purpose: `request(...)` returns `unknown` and the\n * `request*` helpers narrow it at the boundary.\n */\n\ntype Eip1193Object = { [key: string]: Eip1193Value | undefined };\ntype Eip1193Value =\n | bigint\n | boolean\n | number\n | string\n | null\n | Uint8Array\n | ReadonlyArray<Eip1193Value>\n | Eip1193Object;\n\ntype Eip1193RequestArgs = {\n method: string;\n params?: ReadonlyArray<Eip1193Value> | Eip1193Object;\n};\n\ntype Eip1193Listener = (...args: ReadonlyArray<Eip1193Value | undefined>) => void;\n\ntype Eip1193Provider = {\n on: (event: string, listener: Eip1193Listener) => void;\n removeListener: (event: string, listener: Eip1193Listener) => void;\n request: (args: Eip1193RequestArgs) => Promise<Eip1193Value | undefined>;\n};\n\ntype Eip6963ProviderInfo = {\n /** Data URI or absolute URL pointing at the wallet's icon. */\n icon: string;\n /** Human-readable wallet name shown in pickers. */\n name: string;\n /** Reverse-DNS identifier: `io.metamask`, `io.rabby`, `app.phantom`.\n * Stable across versions, unique per wallet, used as the pool key. */\n rdns: string;\n /** Per-page UUID generated by the wallet. Not stable across reloads. */\n uuid: string;\n};\n\ntype Eip6963ProviderDetail = {\n info: Eip6963ProviderInfo;\n provider: Eip1193Provider;\n};\n\ntype Eip6963AnnounceEvent = CustomEvent<Eip6963ProviderDetail>;\n\n/** `provider.request` is typed `unknown` by design; these helpers narrow\n * the well-known EVM RPC shapes at the boundary with runtime guards so\n * call sites stay assertion-free. A malformed response is reported as\n * `null` / `[]` rather than a blank value, so call sites that cannot\n * proceed without a real one fail instead of inventing a default. */\nconst requestString = async (\n provider: Eip1193Provider,\n args: Eip1193RequestArgs,\n): Promise<string | null> => {\n const result = await provider.request(args);\n return typeof result === \"string\" ? result : null;\n};\n\nconst requestStringArray = async (\n provider: Eip1193Provider,\n args: Eip1193RequestArgs,\n): Promise<Array<string>> => {\n const result = await provider.request(args);\n return Array.isArray(result)\n ? result.filter((item): item is string => typeof item === \"string\")\n : [];\n};\n\nexport { requestString, requestStringArray };\n\nexport type {\n Eip1193Listener,\n Eip1193Object,\n Eip1193Provider,\n Eip1193RequestArgs,\n Eip1193Value,\n Eip6963AnnounceEvent,\n Eip6963ProviderDetail,\n Eip6963ProviderInfo,\n};\n","import { hexToBytes } from \"@usebutr/core\";\n\nimport type { Eip1193Provider } from \"./eip1193\";\nimport { requestString } from \"./eip1193\";\n\nconst HEX_PREFIX = \"0x\";\nconst ETH_DECIMALS = 18n;\nconst ERC20_BALANCE_OF_SELECTOR = \"0x70a08231\";\nconst ERC20_DECIMALS_SELECTOR = \"0x313ce567\";\nconst ERC20_SYMBOL_SELECTOR = \"0x95d89b41\";\n\n/** A failed read must not render as a confident zero balance. */\nconst requireHex = (hex: string | null, label: string): string => {\n if (hex === null) {\n throw new Error(`Wallet returned a malformed ${label} response`);\n }\n return hex;\n};\n\nconst formatUnits = (raw: bigint, decimals: number): string => {\n if (decimals === 0) {\n return raw.toString();\n }\n const unit = 10n ** BigInt(decimals);\n const integer = raw / unit;\n const remainder = raw % unit;\n if (remainder === 0n) {\n return integer.toString();\n }\n const fraction = remainder.toString().padStart(decimals, \"0\").replace(/0+$/v, \"\");\n return `${integer}.${fraction}`;\n};\n\nconst formatEther = (wei: bigint): string => formatUnits(wei, Number(ETH_DECIMALS));\n\nconst padAddressForCall = (address: string): string =>\n address.replace(/^0x/v, \"\").toLowerCase().padStart(64, \"0\");\n\nconst decodeAbiString = (hex: string): string => {\n const clean = hex.startsWith(HEX_PREFIX) ? hex.slice(2) : hex;\n if (clean.length === 0) {\n return \"\";\n }\n if (clean.length >= 128) {\n const lengthHex = clean.slice(64, 128);\n const length = Number(BigInt(`0x${lengthHex}`));\n if (length > 0 && clean.length >= 128 + length * 2) {\n return new TextDecoder().decode(hexToBytes(clean.slice(128, 128 + length * 2)));\n }\n }\n const bytes = hexToBytes(clean.slice(0, 64));\n let end = bytes.length;\n while (end > 0 && bytes[end - 1] === 0) {\n end -= 1;\n }\n return new TextDecoder().decode(bytes.subarray(0, end));\n};\n\nconst readEvmBalance = async (\n provider: Eip1193Provider,\n address: string,\n tokenAddress?: string,\n) => {\n if (tokenAddress === undefined || tokenAddress === \"\") {\n const balanceHex = await requestString(provider, {\n method: \"eth_getBalance\",\n params: [address, \"latest\"],\n });\n const value = BigInt(requireHex(balanceHex, \"eth_getBalance\"));\n return {\n decimals: Number(ETH_DECIMALS),\n formatted: formatEther(value),\n symbol: \"ETH\",\n value,\n };\n }\n\n const [balanceHex, decimalsHex, symbolHex] = await Promise.all([\n requestString(provider, {\n method: \"eth_call\",\n params: [\n { data: `${ERC20_BALANCE_OF_SELECTOR}${padAddressForCall(address)}`, to: tokenAddress },\n \"latest\",\n ],\n }),\n requestString(provider, {\n method: \"eth_call\",\n params: [{ data: ERC20_DECIMALS_SELECTOR, to: tokenAddress }, \"latest\"],\n }),\n requestString(provider, {\n method: \"eth_call\",\n params: [{ data: ERC20_SYMBOL_SELECTOR, to: tokenAddress }, \"latest\"],\n }),\n ]);\n const value = BigInt(requireHex(balanceHex, \"balanceOf()\"));\n const decimals = Number(BigInt(requireHex(decimalsHex, \"decimals()\")));\n return {\n decimals,\n formatted: formatUnits(value, decimals),\n symbol: decodeAbiString(symbolHex ?? \"\"),\n value,\n };\n};\n\nexport { formatEther, readEvmBalance };\n","import type { Account, ChainBase, EvmAdapter, EvmTransactionValue } from \"@usebutr/core\";\nimport {\n buildAccount,\n bytesToHexPrefixed,\n EVM_CHAINS_LIST,\n hexToBytes,\n resolveChain,\n sanitizeIcon,\n} from \"@usebutr/core\";\n\nimport type {\n Eip1193Listener,\n Eip1193Object,\n Eip1193Provider,\n Eip1193Value,\n Eip6963ProviderInfo,\n} from \"./eip1193\";\nimport { requestString, requestStringArray } from \"./eip1193\";\nimport { readEvmBalance } from \"./evm-balance\";\n\nconst EVM_NAMESPACE = \"eip155\";\n\nconst toStringArray = (value: Eip1193Value | undefined): Array<string> =>\n Array.isArray(value) ? value.filter((item): item is string => typeof item === \"string\") : [];\n\n/** JSON-RPC cannot carry a `bigint`, so quantities go out as `0x` hex. */\nconst encodeValue = (value: EvmTransactionValue): Eip1193Value => {\n if (typeof value === \"bigint\") {\n return `0x${value.toString(16)}`;\n }\n if (Array.isArray(value)) {\n return value.map(encodeValue);\n }\n if (typeof value !== \"object\" || value === null) {\n return value;\n }\n const result: Eip1193Object = {};\n for (const [key, nested] of Object.entries(value)) {\n result[key] = nested === undefined ? undefined : encodeValue(nested);\n }\n return result;\n};\n\nconst chainIdHexToDecimal = (hex: string): string => BigInt(hex).toString(10);\nconst chainIdDecimalToHex = (dec: string): string => `0x${BigInt(dec).toString(16)}`;\n\nconst evmChainFromHex = (chainIdHex: string): ChainBase =>\n resolveChain(`${EVM_NAMESPACE}:${chainIdHexToDecimal(chainIdHex)}`, EVM_CHAINS_LIST);\n\n/** An event may already carry the addresses or the chain; only the missing\n * half is read back from the wallet. */\ntype KnownAccountState = {\n addresses?: ReadonlyArray<string>;\n chainIdHex?: string;\n};\n\n/** Rejections propagate: `getAccounts` surfaces the wallet's own provider\n * error, while the `subscribe` bridge swallows it because a later event\n * retries synchronization. */\nconst readAccounts = async (\n provider: Eip1193Provider,\n known: KnownAccountState = {},\n): Promise<Array<Account>> => {\n const addresses =\n known.addresses ?? (await requestStringArray(provider, { method: \"eth_accounts\" }));\n if (addresses.length === 0) {\n return [];\n }\n const chainIdHex = known.chainIdHex ?? (await requestString(provider, { method: \"eth_chainId\" }));\n if (chainIdHex === null) {\n throw new Error(\"Wallet returned a malformed eth_chainId response\");\n }\n const chain = evmChainFromHex(chainIdHex);\n return addresses.map((address) => buildAccount(address, chain));\n};\n\n/** EIP-1474 / JSON-RPC codes wallets use for an unimplemented method.\n * Coinbase wraps its own -32604 inside a -32603 `data.originalError`. */\nconst METHOD_NOT_SUPPORTED_CODES = new Set<unknown>([4200, -32_601, -32_603, -32_604]);\n\n/**\n * `disconnect` calls `wallet_revokePermissions`, which many wallets don't\n * implement and silently ignore, so their own auto-reconnect may outlive it.\n * `getBalance()` labels the native balance `\"ETH\"` on every EVM chain.\n */\nconst buildEvmAdapter = (info: Eip6963ProviderInfo, provider: Eip1193Provider): EvmAdapter => {\n /** The address to act as, in the wallet's own casing. Hex addresses are\n * case-insensitive (EIP-55 casing is only a checksum), so they compare\n * lowercased. */\n const resolveAddress = async (account?: Account): Promise<string> => {\n const exposed = await requestStringArray(provider, { method: \"eth_accounts\" });\n if (account === undefined) {\n const active = exposed.at(0);\n if (active === undefined) {\n throw new Error(`Wallet ${info.name} has no connected account`);\n }\n return active;\n }\n const wanted = account.walletAddress.toLowerCase();\n const match = exposed.find((address) => address.toLowerCase() === wanted);\n if (match === undefined) {\n throw new Error(`Wallet ${info.name} does not expose account ${account.walletAddress}`);\n }\n return match;\n };\n\n const switchChain = async (chain: ChainBase): Promise<void> => {\n if (chain.namespace !== EVM_NAMESPACE || !/^\\d+$/v.test(chain.reference)) {\n throw new Error(\n `EVM adapter received non-EVM chain \"${chain.id}\". Pass a chain with namespace \"${EVM_NAMESPACE}\" and a numeric reference.`,\n );\n }\n const target = chainIdDecimalToHex(chain.reference);\n const current = await requestString(provider, { method: \"eth_chainId\" });\n if (current?.toLowerCase() === target) {\n return;\n }\n await provider.request({ method: \"wallet_switchEthereumChain\", params: [{ chainId: target }] });\n };\n\n return {\n chainPlatform: \"evm\",\n\n async connect(options) {\n if (options?.silent === true) {\n const accounts = await requestStringArray(provider, { method: \"eth_accounts\" });\n if (accounts.length === 0) {\n throw new Error(\"No authorized accounts for silent reconnect\");\n }\n return;\n }\n await provider.request({ method: \"eth_requestAccounts\" });\n },\n\n async disconnect() {\n try {\n await provider.request({\n method: \"wallet_revokePermissions\",\n params: [{ eth_accounts: {} }],\n });\n } catch {\n // Many wallets don't implement wallet_revokePermissions yet;\n // not a failure.\n }\n },\n\n getAccounts: () => readAccounts(provider),\n\n async getBalance(options) {\n return readEvmBalance(provider, await resolveAddress(options?.account), options?.token);\n },\n\n getSigner: () => Promise.resolve({ kind: \"eip1193\", provider }),\n\n async getTransactionReceipt(hash) {\n const receipt = await provider.request({\n method: \"eth_getTransactionReceipt\",\n params: [hash],\n });\n // `null` is the RPC's answer for a transaction not yet mined.\n if (receipt === null || typeof receipt !== \"object\" || !(\"status\" in receipt)) {\n return { status: \"Pending\" };\n }\n return { status: receipt.status === \"0x1\" ? \"Success\" : \"Error\" };\n },\n\n icon: sanitizeIcon(info.icon),\n id: info.rdns,\n name: info.name,\n\n async requestAccounts() {\n try {\n await provider.request({\n method: \"wallet_requestPermissions\",\n params: [{ eth_accounts: {} }],\n });\n } catch (error) {\n const outer = typeof error === \"object\" && error !== null ? error : {};\n const data = \"data\" in outer ? outer.data : undefined;\n const inner =\n typeof data === \"object\" && data !== null && \"originalError\" in data\n ? data.originalError\n : undefined;\n const unsupported =\n (\"code\" in outer && METHOD_NOT_SUPPORTED_CODES.has(outer.code)) ||\n (typeof inner === \"object\" &&\n inner !== null &&\n \"code\" in inner &&\n METHOD_NOT_SUPPORTED_CODES.has(inner.code));\n if (!unsupported) {\n throw error;\n }\n await provider.request({ method: \"eth_requestAccounts\" });\n }\n },\n\n // EVM wallets have one global network, so a `chain` switches it before\n // the send rather than routing the one call. `from` is always the\n // resolved account, replacing any `from` inside `tx`.\n async sendTx(tx, options) {\n const from = await resolveAddress(options?.account);\n if (options?.chain !== undefined) {\n await switchChain(options.chain);\n }\n const hash = await requestString(provider, {\n method: \"eth_sendTransaction\",\n params: [encodeValue({ ...tx, from })],\n });\n if (hash === null) {\n throw new Error(\"Wallet returned no transaction hash\");\n }\n return hash;\n },\n\n async signMessage(message, options) {\n const address = await resolveAddress(options?.account);\n const signatureHex = await requestString(provider, {\n method: \"personal_sign\",\n params: [bytesToHexPrefixed(message), address],\n });\n if (signatureHex === null) {\n throw new Error(\"Wallet returned a malformed personal_sign response\");\n }\n return { signature: hexToBytes(signatureHex), signedMessage: message };\n },\n\n subscribe(listener) {\n const synchronize = async (known?: KnownAccountState) => {\n try {\n const accounts = await readAccounts(provider, known);\n if (accounts.length > 0) {\n listener({ accounts, type: \"accountsChanged\" });\n }\n } catch {\n // EIP-1193 event reads are best-effort; a later event retries synchronization.\n }\n };\n\n const onAccountsChanged: Eip1193Listener = (...args) => {\n const addresses = toStringArray(args[0]);\n if (addresses.length === 0) {\n listener({ type: \"disconnected\" });\n return;\n }\n void synchronize({ addresses });\n };\n\n const onChainChanged: Eip1193Listener = (...args) => {\n const [chainId] = args;\n // Some wallets emit a decimal number here instead of the EIP-1193\n // hex string; leaving it absent re-engages the eth_chainId read.\n const chainIdHex = typeof chainId === \"string\" && chainId.length > 0 ? chainId : undefined;\n void synchronize({ chainIdHex });\n };\n\n const onDisconnect: Eip1193Listener = () => {\n listener({ type: \"disconnected\" });\n };\n\n const onConnect: Eip1193Listener = () => {\n void synchronize();\n };\n\n provider.on(\"accountsChanged\", onAccountsChanged);\n provider.on(\"chainChanged\", onChainChanged);\n provider.on(\"connect\", onConnect);\n provider.on(\"disconnect\", onDisconnect);\n\n return () => {\n provider.removeListener(\"accountsChanged\", onAccountsChanged);\n provider.removeListener(\"chainChanged\", onChainChanged);\n provider.removeListener(\"connect\", onConnect);\n provider.removeListener(\"disconnect\", onDisconnect);\n };\n },\n\n switchChain,\n };\n};\n\nexport { formatEther } from \"./evm-balance\";\nexport { buildEvmAdapter, chainIdDecimalToHex, chainIdHexToDecimal };\n","import type { EvmAdapter } from \"@usebutr/core\";\n\nimport type { Eip6963AnnounceEvent, Eip6963ProviderInfo } from \"./eip1193\";\nimport { buildEvmAdapter } from \"./eip6963-adapter\";\n\nconst ANNOUNCE_EVENT = \"eip6963:announceProvider\";\nconst REQUEST_EVENT = \"eip6963:requestProvider\";\n\ntype AdapterCallback = (adapter: EvmAdapter, info: Eip6963ProviderInfo) => void;\n\ntype DiscoverOptions = {\n /** Event target to listen on. Defaults to `window` in browser/RN/\n * SSR'd environments; tests can pass a fresh `new EventTarget()` to\n * exercise the discovery loop without a DOM. */\n target?: EventTarget;\n};\n\nconst isEip6963AnnounceEvent = (event: Event): event is Eip6963AnnounceEvent => {\n if (!(\"detail\" in event)) {\n return false;\n }\n const detail: unknown = event.detail;\n if (typeof detail !== \"object\" || detail === null) {\n return false;\n }\n if (!(\"info\" in detail) || !(\"provider\" in detail)) {\n return false;\n }\n const { info, provider } = detail;\n return (\n typeof info === \"object\" &&\n info !== null &&\n \"icon\" in info &&\n typeof info.icon === \"string\" &&\n \"name\" in info &&\n typeof info.name === \"string\" &&\n \"rdns\" in info &&\n typeof info.rdns === \"string\" &&\n \"uuid\" in info &&\n typeof info.uuid === \"string\" &&\n typeof provider === \"object\" &&\n provider !== null &&\n \"on\" in provider &&\n typeof provider.on === \"function\" &&\n \"removeListener\" in provider &&\n typeof provider.removeListener === \"function\" &&\n \"request\" in provider &&\n typeof provider.request === \"function\"\n );\n};\n\nconst windowGlobal: Partial<Pick<typeof globalThis, \"window\">> = globalThis;\n\nconst resolveTarget = (target?: EventTarget): EventTarget | null => {\n if (target !== undefined) {\n return target;\n }\n return windowGlobal.window ?? null;\n};\n\n/**\n * Spec: https://eips.ethereum.org/EIPS/eip-6963. Dedupe is by `info.rdns`\n * because `info.uuid` is regenerated per page load. The listener stays\n * attached for the session so wallets that boot late still register.\n */\nconst discoverEvmAdapters = (\n onAdapter: AdapterCallback,\n options: DiscoverOptions = {},\n): (() => void) => {\n const target = resolveTarget(options.target);\n if (!target) {\n return () => {};\n }\n\n const seen = new Set<string>();\n const handler = (event: Event) => {\n if (!isEip6963AnnounceEvent(event)) {\n return;\n }\n const { info, provider } = event.detail;\n if (info.rdns.length === 0) {\n return;\n }\n if (seen.has(info.rdns)) {\n return;\n }\n seen.add(info.rdns);\n onAdapter(buildEvmAdapter(info, provider), info);\n };\n\n target.addEventListener(ANNOUNCE_EVENT, handler);\n target.dispatchEvent(new Event(REQUEST_EVENT));\n\n return () => {\n target.removeEventListener(ANNOUNCE_EVENT, handler);\n };\n};\n\nexport { ANNOUNCE_EVENT, REQUEST_EVENT, discoverEvmAdapters };\n","import type { EvmAdapter } from \"@usebutr/core\";\n\nimport type { Eip1193Provider, Eip6963ProviderInfo } from \"./eip1193\";\nimport { buildEvmAdapter } from \"./eip6963-adapter\";\n\n/**\n * Generic wallet icon (a stylised purse SVG, ~600 bytes). Used as\n * the fallback icon when an injected provider has no EIP-6963 info.\n * Inline rather than a network fetch so the picker doesn't flicker.\n */\nconst GENERIC_INJECTED_ICON =\n \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj48cGF0aCBkPSJNMjEgMTJWN0g1YTIgMiAwIDAgMSAwLTQgaDE0djQiLz48cGF0aCBkPSJNMyA1djE0YTIgMiAwIDAgMCAyIDJoMTZ2LTVNMjEgMTIgaC0zYTIgMiAwIDAgMC0yIDJ2MGEyIDIgMCAwIDAgMiAyaDN6Ii8+PC9zdmc+\";\n\nconst DEFAULT_SETTLE_MS = 150;\n\ntype InjectedDiscoveryOptions = {\n /**\n * Consulted before emitting: an already-registered EIP-6963 adapter means\n * the wallet is covered by the standards path and emitting would duplicate\n * it. Omit to always emit.\n */\n hasAnyEip6963Adapter?: () => boolean;\n /**\n * Most wallets announce within the first frame; 150ms leaves room for slow\n * announcements without stalling the picker.\n */\n settleMs?: number;\n /** Override the global `window` reference (tests, iframes). */\n target?: { ethereum?: Partial<Eip1193Provider> } | null;\n};\n\ndeclare global {\n // oxlint-disable-next-line typescript/consistent-type-definitions -- DOM globals require interface merging.\n interface Window {\n ethereum?: Partial<Eip1193Provider>;\n }\n}\n\n/** Structural check for code that holds a provider of unknown origin, such\n * as `window.ethereum`. A butr signer narrows on `kind === \"eip1193\"`\n * instead. */\nconst isEip1193Provider = (value: unknown): value is Eip1193Provider =>\n typeof value === \"object\" &&\n value !== null &&\n \"on\" in value &&\n typeof value.on === \"function\" &&\n \"removeListener\" in value &&\n typeof value.removeListener === \"function\" &&\n \"request\" in value &&\n typeof value.request === \"function\";\n\nconst readEthereum = (target: InjectedDiscoveryOptions[\"target\"]): Eip1193Provider | null => {\n const host = target === undefined ? globalThis.window : target;\n return isEip1193Provider(host?.ethereum) ? host.ethereum : null;\n};\n\n/**\n * Last-resort path for the long tail of EVM wallets that expose only\n * `window.ethereum` and never announce via EIP-6963. The emitted adapter\n * carries `rdns: \"injected:legacy\"` so consumers can tell it apart.\n */\nconst discoverInjectedAdapter = (\n onAdapter: (adapter: EvmAdapter) => void,\n options: InjectedDiscoveryOptions = {},\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.hasAnyEip6963Adapter?.() === true) {\n return;\n }\n const provider = readEthereum(options.target);\n if (provider === null) {\n return;\n }\n const info: Eip6963ProviderInfo = {\n icon: GENERIC_INJECTED_ICON,\n name: \"Browser wallet\",\n rdns: \"injected:legacy\",\n uuid: \"injected:legacy\",\n };\n onAdapter(buildEvmAdapter(info, provider));\n }, settleMs);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n};\n\nexport type { InjectedDiscoveryOptions };\nexport { GENERIC_INJECTED_ICON, discoverInjectedAdapter, isEip1193Provider };\n","import type { PlatformDiscoverer } from \"@usebutr/core\";\n\nimport { discoverEvmAdapters } from \"./eip6963\";\nimport { discoverInjectedAdapter } from \"./injected\";\n\n/**\n * EIP-6963 is primary; the legacy `window.ethereum` fallback defers until\n * EIP-6963 has had a chance to fire.\n */\nconst evmDiscoverer: PlatformDiscoverer = {\n fallback: {\n subscribe: (onAdapter, opts) =>\n discoverInjectedAdapter(onAdapter, {\n hasAnyEip6963Adapter: opts.hasAnyPrimaryAdapter,\n }),\n },\n subscribe: discoverEvmAdapters,\n};\n\nexport { evmDiscoverer };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usebutr/evm",
3
- "version": "1.1.1",
3
+ "version": "2.0.0",
4
4
  "description": "EIP-1193 / EIP-6963 / injected wallet discovery + adapters for butr.",
5
5
  "keywords": [
6
6
  "butr",
@@ -41,11 +41,11 @@
41
41
  "access": "public"
42
42
  },
43
43
  "dependencies": {
44
- "@usebutr/core": "2.0.1"
44
+ "@usebutr/core": "3.0.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "typescript": "^7.0.2",
48
- "vitest": "^4.1.10",
48
+ "vitest": "^5.0.0",
49
49
  "@repo/config-vitest": "0.0.0",
50
50
  "@repo/typescript-config": "0.0.0"
51
51
  },