@tuwaio/satellite-evm 1.0.0-fix-watcher-alpha.3.b979b45 → 1.0.0-fix-error-handling-alpha.2.5165cfe

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/README.md CHANGED
@@ -18,7 +18,6 @@ Built on top of `@tuwaio/satellite-core`, this package integrates seamlessly wit
18
18
 
19
19
  ## ✨ Key Features
20
20
 
21
- - **EVM Wallet Support:** Native support for popular EVM wallets
22
21
  - **Chain Management:** Built-in utilities for handling multiple EVM chains
23
22
  - **Type Safety:** Full TypeScript support with proper type definitions
24
23
  - **Wagmi Integration:** Seamless integration with @wagmi/core utilities
@@ -30,18 +29,12 @@ Built on top of `@tuwaio/satellite-core`, this package integrates seamlessly wit
30
29
 
31
30
  ### Requirements
32
31
 
33
- - Node.js 20+
32
+ - Node.js 20-24
34
33
  - TypeScript 5.9+
35
34
 
36
35
  ```bash
37
- # Using pnpm (recommended)
36
+ # Using pnpm (recommended), but you can use npm, yarn or bun as well
38
37
  pnpm add @tuwaio/satellite-evm @tuwaio/satellite-core viem @wagmi/core immer zustand @tuwaio/orbit-core @tuwaio/orbit-evm
39
-
40
- # Using npm
41
- npm install @tuwaio/satellite-evm @tuwaio/satellite-core viem @wagmi/core immer zustand @tuwaio/orbit-core @tuwaio/orbit-evm
42
-
43
- # Using yarn
44
- yarn add @tuwaio/satellite-evm @tuwaio/satellite-core viem @wagmi/core immer zustand @tuwaio/orbit-core @tuwaio/orbit-evm
45
38
  ````
46
39
 
47
40
  -----
@@ -84,7 +77,7 @@ You create the adapter by passing your `wagmiConfig` to the `satelliteEVMAdapter
84
77
  import { satelliteEVMAdapter } from '@tuwaio/satellite-evm';
85
78
  import { wagmiConfig } from './your-wagmi-config'; // Import your configured wagmiConfig
86
79
 
87
- const evmAdapter = satelliteEVMAdapter(wagmiConfig);
80
+ export const evmAdapter = satelliteEVMAdapter(wagmiConfig);
88
81
  ```
89
82
 
90
83
  ### Integrating with Satellite Connect Provider
@@ -96,13 +89,12 @@ import { SatelliteConnectProvider, EVMConnectorsWatcher } from '@tuwaio/satellit
96
89
  import { WagmiProvider } from 'wagmi';
97
90
  import { satelliteEVMAdapter } from '@tuwaio/satellite-evm';
98
91
  import { wagmiConfig } from './your-wagmi-config';
92
+ import { evmAdapter } from './your-evm-adapter';
99
93
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; // Wagmi requires react-query
100
94
 
101
95
  const queryClient = new QueryClient();
102
96
 
103
97
  function AppProviders({ children }: { children: React.ReactNode }) {
104
- const evmAdapter = satelliteEVMAdapter(wagmiConfig);
105
-
106
98
  return (
107
99
  <WagmiProvider config={wagmiConfig}>
108
100
  <QueryClientProvider client={queryClient}>
@@ -128,7 +120,7 @@ The `satelliteEVMAdapter` seamlessly integrates with SIWE solutions like `@tuwai
128
120
  This ensures that the SIWE flow is automatically triggered after a successful wallet connection.
129
121
 
130
122
  ```tsx
131
- // Example within a React component using @tuwaio/satellite-siwe-next-auth
123
+ // Example: SIWE integration with @tuwaio/satellite-siwe-next-auth
132
124
 
133
125
  import { useSiweAuth, SiweNextAuthProvider } from '@tuwaio/satellite-siwe-next-auth';
134
126
  import { SatelliteConnectProvider } from '@tuwaio/satellite-react';
@@ -137,50 +129,65 @@ import { satelliteEVMAdapter } from '@tuwaio/satellite-evm';
137
129
  import { WagmiProvider } from 'wagmi';
138
130
  import { wagmiConfig } from './your-wagmi-config'; // Your Wagmi config
139
131
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
132
+ import { ReactNode, useState } from 'react';
140
133
 
141
- const queryClient = new QueryClient();
142
-
143
- function App() {
144
- // Assuming SiweNextAuthProvider is wrapping this component higher up
134
+ // Step 1: Create SatelliteConnectProvider wrapper that consumes SIWE context
135
+ function SatelliteSiweProvider({ children }: { children: ReactNode }) {
136
+ // Get SIWE auth state and methods from the provider above
145
137
  const { signInWithSiwe, enabled: siweEnabled, isRejected, isSignedIn } = useSiweAuth();
146
138
 
147
- // Create the adapter, passing signInWithSiwe if SIWE is enabled
148
- const evmAdapter = satelliteEVMAdapter(wagmiConfig, siweEnabled ? signInWithSiwe : undefined);
149
-
150
139
  return (
151
- <SatelliteConnectProvider
152
- adapter={evmAdapter}
153
- autoConnect={true}
154
- >
155
- {/* Pass siwe state to watcher for handling disconnections on SIWE rejection */}
156
- <EVMConnectorsWatcher wagmiConfig={wagmiConfig} siwe={{ isSignedIn, isRejected, enabled: siweEnabled }} />
157
- {/* Your application components */}
158
- </SatelliteConnectProvider>
140
+ <SatelliteConnectProvider
141
+ // Create the adapter, passing signInWithSiwe if SIWE is enabled
142
+ adapter={satelliteEVMAdapter(wagmiConfig, siweEnabled ? signInWithSiwe : undefined)}
143
+ autoConnect={true}
144
+ >
145
+ {/* Pass SIWE state to watcher for handling disconnections on SIWE rejection */}
146
+ <EVMConnectorsWatcher wagmiConfig={wagmiConfig} siwe={{ isSignedIn, isRejected, enabled: siweEnabled }} />
147
+ {children}
148
+ </SatelliteConnectProvider>
159
149
  );
160
150
  }
161
151
 
152
+ // Step 2: Compose all providers in the correct order
153
+ // Create QueryClient
154
+ const queryClient = new QueryClient();
162
155
 
163
- // Wrap your main application layout with necessary providers
164
- function RootLayout({ children }: { children: React.ReactNode }) {
165
- return (
156
+ function Providers({ children }: { children: ReactNode }) {
157
+ return (
166
158
  <WagmiProvider config={wagmiConfig}>
167
159
  <QueryClientProvider client={queryClient}>
168
- {/* SIWE Provider wraps SatelliteConnectProvider */}
160
+ {/* SIWE Provider must wrap SatelliteSiweProvider to provide context */}
169
161
  <SiweNextAuthProvider wagmiConfig={wagmiConfig} enabled={true}>
170
- {children} {/* App component will be rendered here */}
162
+ <SatelliteSiweProvider>
163
+ {children}
164
+ </SatelliteSiweProvider>
171
165
  </SiweNextAuthProvider>
172
166
  </QueryClientProvider>
173
167
  </WagmiProvider>
174
- );
168
+ );
169
+ }
170
+
171
+ // Step 3: Use Providers in your application layout
172
+ function RootLayout({ children }: { children: React.ReactNode }) {
173
+ return (
174
+ <Providers>
175
+ {/* Your application components */}
176
+ {children}
177
+ </Providers>
178
+ );
175
179
  }
176
180
  ```
177
181
 
178
182
  -----
179
183
 
180
- ## 🛠️ Core Utilities
184
+ - ## 🛠️ Core Utilities
181
185
 
182
186
  - **`createDefaultTransports`**: Helper to create default `http` transports for each chain in your `wagmiConfig`.
183
187
  - **`checkIsWalletAddressContract`**: Utility to check if a connected address is a smart contract address. The result is cached in memory.
188
+ - **`createEVMConnectionsWatcher`**: Framework-agnostic utility to monitor wagmi connection changes and synchronize them with the global state store. Handles account switches, network changes, disconnections, and optional SIWE rejection scenarios. Returns a cleanup function.
189
+
190
+ -----
184
191
 
185
192
  ## 🤝 Contributing & Support
186
193
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var orbitCore=require('@tuwaio/orbit-core'),orbitEvm=require('@tuwaio/orbit-evm'),core=require('@wagmi/core'),viem=require('viem'),chains=require('viem/chains'),utils=require('viem/utils');var g=new Map;async function b({config:c,address:o,chainId:e,chains:r}){if(g.has(o))return g.get(o);if(orbitEvm.createViemClient(e,r)){let n=!!await core.getBytecode(c,{address:o});return g.set(o,n),n}else return false}function fe(c,o){if(!c)throw new Error("Satellite EVM adapter requires a wagmi config object.");return {key:orbitCore.OrbitAdapter.EVM,connect:async({connectorType:e,chainId:r})=>{let a=core.getConnectors(c).find(n=>orbitCore.getConnectorTypeFromName(orbitCore.OrbitAdapter.EVM,orbitCore.formatConnectorName(n.name))===e);if(!a)throw new Error("Cannot find connector with this wallet type");try{await core.connect(c,{connector:a,chainId:r}),o&&!orbitCore.isSafeApp&&orbitCore.formatConnectorName(a.name)!=="porto"&&orbitCore.formatConnectorName(a.name)!=="geminiwallet"&&orbitCore.formatConnectorName(a.name)!=="Impersonatedconnector"&&await o();let n=core.getConnection(c);return {connectorType:e,address:n.address??viem.zeroAddress,chainId:n.chainId??chains.mainnet.id,rpcURL:n.chain?.rpcUrls.default.http[0]??chains.mainnet.rpcUrls.default.http[0],isConnected:n.isConnected,isContractAddress:!1,icon:a?.icon?.trim(),connector:a}}catch(n){throw new Error(n instanceof Error?n.message:String(n))}},disconnect:async e=>{if(e&&e.isConnected)await core.disconnect(c,{connector:e?.connector});else {let r=core.getConnectors(c);await Promise.allSettled(r.map(async t=>{await core.disconnect(c,{connector:t});}));}},getConnectors:()=>{let e=core.getConnectors(c);return {adapter:orbitCore.OrbitAdapter.EVM,connectors:e.map(r=>r)}},checkAndSwitchNetwork:async e=>await orbitEvm.checkAndSwitchChain(Number(e),c),getBalance:async(e,r)=>{let t=await core.getBalance(c,{address:e,chainId:Number(r)});return {value:viem.formatUnits(t.value,t.decimals),symbol:t.symbol}},getExplorerUrl:e=>{let{chain:r}=core.getConnection(c),t=r?.blockExplorers?.default.url;return e?`${t}/${e}`:t},getName:e=>orbitEvm.getName(e),getAvatar:e=>orbitEvm.getAvatar(e),getAddress:e=>orbitEvm.getAddress(e),checkIsContractAddress:async({address:e,chainId:r})=>{let t=core.getChains(c);return await b({config:c,address:e,chainId:r,chains:t})},getSafeConnectorChainId:async()=>{let r=core.getConnectors(c).find(t=>t.name==="Safe");if(r)return await r.getChainId()},switchConnection:async e=>{let t=core.getConnectors(c).find(a=>orbitCore.getConnectorTypeFromName(orbitCore.OrbitAdapter.EVM,orbitCore.formatConnectorName(a.name))===e);if(!t)throw new Error(`Cannot find connector with type: ${e}`);try{await core.switchConnection(c,{connector:t});}catch(a){throw new Error(`Failed to switch to connector ${e}: ${a instanceof Error?a.message:String(a)}`)}}}}S.type="impersonated";function S(c){let o=c.features??{},e=false,r,t;return core.createConnector(a=>({id:"impersonated",name:"Impersonated Connector",type:S.type,async setup(){r=a.chains[0].id;},async connect({chainId:n}={}){if(o.connectError)throw typeof o.connectError=="boolean"?new viem.UserRejectedRequestError(new Error("Failed to connect.")):o.connectError;let{request:s}=await this.getProvider(),d=await s({method:"eth_requestAccounts"}),h=await this.getChainId();return n&&h!==n&&(h=(await this.switchChain({chainId:n})).id),e=true,{accounts:d,chainId:h}},async disconnect(){e=false,t=void 0;},async getAccounts(){if(!e)throw new Error("Not connected connector");let{request:n}=await this.getProvider();return (await n({method:"eth_accounts"})).map(viem.getAddress)},async getChainId(){let{request:n}=await this.getProvider(),s=await n({method:"eth_chainId"});return viem.fromHex(s,"number")},async isAuthorized(){return e?!!(await this.getAccounts()).length:false},async switchChain({chainId:n}){let s=a.chains.find(h=>h.id===n);if(!s)throw new viem.SwitchChainError(new core.ChainNotConfiguredError);let{request:d}=await this.getProvider();return await d({method:"wallet_switchEthereumChain",params:[{chainId:viem.numberToHex(n)}]}),s},onAccountsChanged(n){n.length===0?this.onDisconnect():a.emitter.emit("change",{accounts:n.map(viem.getAddress)});},onChainChanged(n){let s=Number(n);a.emitter.emit("change",{chainId:s});},async onDisconnect(){a.emitter.emit("disconnect"),e=false,t=void 0;},async getProvider({chainId:n}={}){t=orbitCore.impersonatedHelpers?.getImpersonated()?[orbitCore.impersonatedHelpers.getImpersonated()||viem.zeroAddress]:void 0;let d=(a.chains.find(i=>i.id===n)??a.chains[0]).rpcUrls.default.http[0];return viem.custom({request:async({method:i,params:p})=>{if(i==="eth_chainId")return viem.numberToHex(r);if(i==="eth_requestAccounts")return t;if(i==="eth_signTypedData_v4"&&o.signTypedDataError)throw typeof o.signTypedDataError=="boolean"?new viem.UserRejectedRequestError(new Error("Failed to sign typed data.")):o.signTypedDataError;if(i==="wallet_switchEthereumChain"){if(o.switchChainError)throw typeof o.switchChainError=="boolean"?new viem.UserRejectedRequestError(new Error("Failed to switch chain.")):o.switchChainError;r=viem.fromHex(p[0].chainId,"number"),this.onChainChanged(r.toString());return}if(i==="personal_sign"){if(o.signMessageError)throw typeof o.signMessageError=="boolean"?new viem.UserRejectedRequestError(new Error("Failed to sign message.")):o.signMessageError;i="eth_sign",p=[p[1],p[0]];}let m={method:i,params:p},{error:u,result:y}=await utils.rpc.http(d,{body:m});if(u)throw new viem.RpcRequestError({body:m,error:u,url:d});return y}})({retryCount:1})}}))}var Ae={allowedDomains:[/gnosis-safe.io$/,/app.safe.global$/,/metissafe.tech$/],debug:false};var Te=c=>c.reduce((o,e)=>{let r=e.id;return o[r]=viem.http(),o},{});function Ne(c,o){let{wagmiConfig:e,siwe:r}=c,{activeConnection:t,disconnect:a,connectionError:n,updateActiveConnection:s}=o,d=()=>{r?.enabled&&!r?.isSignedIn&&r?.isRejected&&t&&a(t.connectorType);},h=p=>{if(t&&orbitCore.getAdapterFromConnectorType(t.connectorType)!==orbitCore.OrbitAdapter.EVM)return;if(p.length===0){t&&a(t.connectorType);return}let m=core.getConnection(e);if(t&&orbitCore.getAdapterFromConnectorType(t.connectorType)!==orbitCore.OrbitAdapter.EVM||!m||n)return;let u=m.connector,k={connectorType:u?`${orbitCore.OrbitAdapter.EVM}:${orbitCore.formatConnectorName(u.name)}`:t?.connectorType,address:m.address,chainId:m.chainId,rpcURL:m?.chain?.rpcUrls.default.http[0],isConnected:true};s(k);};return d(),core.watchConnections(e,{onChange:h})}exports.checkIsWalletAddressContract=b;exports.createDefaultTransports=Te;exports.createEVMConnectionsWatcher=Ne;exports.impersonated=S;exports.safeSdkOptions=Ae;exports.satelliteEVMAdapter=fe;
1
+ 'use strict';var orbitCore=require('@tuwaio/orbit-core'),orbitEvm=require('@tuwaio/orbit-evm'),core=require('@wagmi/core'),viem=require('viem'),chains=require('viem/chains'),utils=require('viem/utils');var g=new Map;async function b({config:c,address:o,chainId:e,chains:r}){if(g.has(o))return g.get(o);if(orbitEvm.createViemClient(e,r)){let n=!!await core.getBytecode(c,{address:o});return g.set(o,n),n}else return false}function fe(c,o){if(!c)throw new Error("Satellite EVM adapter requires a wagmi config object.");return {key:orbitCore.OrbitAdapter.EVM,connect:async({connectorType:e,chainId:r})=>{let a=core.getConnectors(c).find(n=>orbitCore.getConnectorTypeFromName(orbitCore.OrbitAdapter.EVM,orbitCore.formatConnectorName(n.name))===e);if(!a)throw new Error("Cannot find connector with this wallet type");try{await core.connect(c,{connector:a,chainId:r}),o&&!orbitCore.isSafeApp&&orbitCore.formatConnectorName(a.name)!=="porto"&&orbitCore.formatConnectorName(a.name)!=="geminiwallet"&&orbitCore.formatConnectorName(a.name)!=="impersonatedwallet"&&await o();let n=core.getConnection(c);return {connectorType:e,address:n.address??viem.zeroAddress,chainId:n.chainId??chains.mainnet.id,rpcURL:n.chain?.rpcUrls.default.http[0]??chains.mainnet.rpcUrls.default.http[0],isConnected:n.isConnected,isContractAddress:!1,icon:a?.icon?.trim(),connector:a}}catch(n){throw new Error(n instanceof Error?n.message:String(n))}},disconnect:async e=>{if(e&&e.isConnected)await core.disconnect(c,{connector:e?.connector});else {let r=core.getConnectors(c);await Promise.allSettled(r.map(async t=>{await core.disconnect(c,{connector:t});}));}},getConnectors:()=>{let e=core.getConnectors(c);return {adapter:orbitCore.OrbitAdapter.EVM,connectors:e.map(r=>r)}},checkAndSwitchNetwork:async e=>await orbitEvm.checkAndSwitchChain(Number(e),c),getBalance:async(e,r)=>{let t=await core.getBalance(c,{address:e,chainId:Number(r)});return {value:viem.formatUnits(t.value,t.decimals),symbol:t.symbol}},getExplorerUrl:e=>{let{chain:r}=core.getConnection(c),t=r?.blockExplorers?.default.url;return e?`${t}/${e}`:t},getName:e=>orbitEvm.getName(e),getAvatar:e=>orbitEvm.getAvatar(e),getAddress:e=>orbitEvm.getAddress(e),checkIsContractAddress:async({address:e,chainId:r})=>{let t=core.getChains(c);return await b({config:c,address:e,chainId:r,chains:t})},getSafeConnectorChainId:async()=>{let r=core.getConnectors(c).find(t=>t.name==="Safe");if(r)return await r.getChainId()},switchConnection:async e=>{let t=core.getConnectors(c).find(a=>orbitCore.getConnectorTypeFromName(orbitCore.OrbitAdapter.EVM,orbitCore.formatConnectorName(a.name))===e);if(!t)throw new Error(`Cannot find connector with type: ${e}`);try{await core.switchConnection(c,{connector:t});}catch(a){throw new Error(`Failed to switch to connector ${e}: ${a instanceof Error?a.message:String(a)}`)}}}}S.type="impersonated";function S(c){let o=c.features??{},e=false,r,t;return core.createConnector(a=>({id:"impersonated",name:"Impersonated Connector",type:S.type,async setup(){r=a.chains[0].id;},async connect({chainId:n}={}){if(o.connectError)throw typeof o.connectError=="boolean"?new viem.UserRejectedRequestError(new Error("Failed to connect.")):o.connectError;let{request:s}=await this.getProvider(),d=await s({method:"eth_requestAccounts"}),h=await this.getChainId();return n&&h!==n&&(h=(await this.switchChain({chainId:n})).id),e=true,{accounts:d,chainId:h}},async disconnect(){e=false,t=void 0;},async getAccounts(){if(!e)throw new Error("Not connected connector");let{request:n}=await this.getProvider();return (await n({method:"eth_accounts"})).map(viem.getAddress)},async getChainId(){let{request:n}=await this.getProvider(),s=await n({method:"eth_chainId"});return viem.fromHex(s,"number")},async isAuthorized(){return e?!!(await this.getAccounts()).length:false},async switchChain({chainId:n}){let s=a.chains.find(h=>h.id===n);if(!s)throw new viem.SwitchChainError(new core.ChainNotConfiguredError);let{request:d}=await this.getProvider();return await d({method:"wallet_switchEthereumChain",params:[{chainId:viem.numberToHex(n)}]}),s},onAccountsChanged(n){n.length===0?this.onDisconnect():a.emitter.emit("change",{accounts:n.map(viem.getAddress)});},onChainChanged(n){let s=Number(n);a.emitter.emit("change",{chainId:s});},async onDisconnect(){a.emitter.emit("disconnect"),e=false,t=void 0;},async getProvider({chainId:n}={}){t=orbitCore.impersonatedHelpers?.getImpersonated()?[orbitCore.impersonatedHelpers.getImpersonated()||viem.zeroAddress]:void 0;let d=(a.chains.find(i=>i.id===n)??a.chains[0]).rpcUrls.default.http[0];return viem.custom({request:async({method:i,params:p})=>{if(i==="eth_chainId")return viem.numberToHex(r);if(i==="eth_requestAccounts")return t;if(i==="eth_signTypedData_v4"&&o.signTypedDataError)throw typeof o.signTypedDataError=="boolean"?new viem.UserRejectedRequestError(new Error("Failed to sign typed data.")):o.signTypedDataError;if(i==="wallet_switchEthereumChain"){if(o.switchChainError)throw typeof o.switchChainError=="boolean"?new viem.UserRejectedRequestError(new Error("Failed to switch chain.")):o.switchChainError;r=viem.fromHex(p[0].chainId,"number"),this.onChainChanged(r.toString());return}if(i==="personal_sign"){if(o.signMessageError)throw typeof o.signMessageError=="boolean"?new viem.UserRejectedRequestError(new Error("Failed to sign message.")):o.signMessageError;i="eth_sign",p=[p[1],p[0]];}let m={method:i,params:p},{error:u,result:y}=await utils.rpc.http(d,{body:m});if(u)throw new viem.RpcRequestError({body:m,error:u,url:d});return y}})({retryCount:1})}}))}var Ae={allowedDomains:[/gnosis-safe.io$/,/app.safe.global$/,/metissafe.tech$/],debug:false};var Te=c=>c.reduce((o,e)=>{let r=e.id;return o[r]=viem.http(),o},{});function Ne(c,o){let{wagmiConfig:e,siwe:r}=c,{activeConnection:t,disconnect:a,connectionError:n,updateActiveConnection:s}=o,d=()=>{r?.enabled&&!r?.isSignedIn&&r?.isRejected&&t&&a(t.connectorType);},h=p=>{if(t&&orbitCore.getAdapterFromConnectorType(t.connectorType)!==orbitCore.OrbitAdapter.EVM)return;if(p.length===0){t&&a(t.connectorType);return}let m=core.getConnection(e);if(t&&orbitCore.getAdapterFromConnectorType(t.connectorType)!==orbitCore.OrbitAdapter.EVM||!m||n)return;let u=m.connector,k={connectorType:u?`${orbitCore.OrbitAdapter.EVM}:${orbitCore.formatConnectorName(u.name)}`:t?.connectorType,address:m.address,chainId:m.chainId,rpcURL:m?.chain?.rpcUrls.default.http[0],isConnected:true};s(k);};return d(),core.watchConnections(e,{onChange:h})}exports.checkIsWalletAddressContract=b;exports.createDefaultTransports=Te;exports.createEVMConnectionsWatcher=Ne;exports.impersonated=S;exports.safeSdkOptions=Ae;exports.satelliteEVMAdapter=fe;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import {OrbitAdapter,getConnectorTypeFromName,formatConnectorName,isSafeApp,impersonatedHelpers,getAdapterFromConnectorType}from'@tuwaio/orbit-core';import {createViemClient,getAddress,getAvatar,getName,checkAndSwitchChain}from'@tuwaio/orbit-evm';import {getBytecode,getConnectors,switchConnection,getChains,getConnection,getBalance,disconnect,connect,createConnector,ChainNotConfiguredError,watchConnections}from'@wagmi/core';import {formatUnits,zeroAddress,custom,numberToHex,UserRejectedRequestError,fromHex,RpcRequestError,getAddress as getAddress$1,SwitchChainError,http}from'viem';import {mainnet}from'viem/chains';import {rpc}from'viem/utils';var g=new Map;async function b({config:c,address:o,chainId:e,chains:r}){if(g.has(o))return g.get(o);if(createViemClient(e,r)){let n=!!await getBytecode(c,{address:o});return g.set(o,n),n}else return false}function fe(c,o){if(!c)throw new Error("Satellite EVM adapter requires a wagmi config object.");return {key:OrbitAdapter.EVM,connect:async({connectorType:e,chainId:r})=>{let a=getConnectors(c).find(n=>getConnectorTypeFromName(OrbitAdapter.EVM,formatConnectorName(n.name))===e);if(!a)throw new Error("Cannot find connector with this wallet type");try{await connect(c,{connector:a,chainId:r}),o&&!isSafeApp&&formatConnectorName(a.name)!=="porto"&&formatConnectorName(a.name)!=="geminiwallet"&&formatConnectorName(a.name)!=="Impersonatedconnector"&&await o();let n=getConnection(c);return {connectorType:e,address:n.address??zeroAddress,chainId:n.chainId??mainnet.id,rpcURL:n.chain?.rpcUrls.default.http[0]??mainnet.rpcUrls.default.http[0],isConnected:n.isConnected,isContractAddress:!1,icon:a?.icon?.trim(),connector:a}}catch(n){throw new Error(n instanceof Error?n.message:String(n))}},disconnect:async e=>{if(e&&e.isConnected)await disconnect(c,{connector:e?.connector});else {let r=getConnectors(c);await Promise.allSettled(r.map(async t=>{await disconnect(c,{connector:t});}));}},getConnectors:()=>{let e=getConnectors(c);return {adapter:OrbitAdapter.EVM,connectors:e.map(r=>r)}},checkAndSwitchNetwork:async e=>await checkAndSwitchChain(Number(e),c),getBalance:async(e,r)=>{let t=await getBalance(c,{address:e,chainId:Number(r)});return {value:formatUnits(t.value,t.decimals),symbol:t.symbol}},getExplorerUrl:e=>{let{chain:r}=getConnection(c),t=r?.blockExplorers?.default.url;return e?`${t}/${e}`:t},getName:e=>getName(e),getAvatar:e=>getAvatar(e),getAddress:e=>getAddress(e),checkIsContractAddress:async({address:e,chainId:r})=>{let t=getChains(c);return await b({config:c,address:e,chainId:r,chains:t})},getSafeConnectorChainId:async()=>{let r=getConnectors(c).find(t=>t.name==="Safe");if(r)return await r.getChainId()},switchConnection:async e=>{let t=getConnectors(c).find(a=>getConnectorTypeFromName(OrbitAdapter.EVM,formatConnectorName(a.name))===e);if(!t)throw new Error(`Cannot find connector with type: ${e}`);try{await switchConnection(c,{connector:t});}catch(a){throw new Error(`Failed to switch to connector ${e}: ${a instanceof Error?a.message:String(a)}`)}}}}S.type="impersonated";function S(c){let o=c.features??{},e=false,r,t;return createConnector(a=>({id:"impersonated",name:"Impersonated Connector",type:S.type,async setup(){r=a.chains[0].id;},async connect({chainId:n}={}){if(o.connectError)throw typeof o.connectError=="boolean"?new UserRejectedRequestError(new Error("Failed to connect.")):o.connectError;let{request:s}=await this.getProvider(),d=await s({method:"eth_requestAccounts"}),h=await this.getChainId();return n&&h!==n&&(h=(await this.switchChain({chainId:n})).id),e=true,{accounts:d,chainId:h}},async disconnect(){e=false,t=void 0;},async getAccounts(){if(!e)throw new Error("Not connected connector");let{request:n}=await this.getProvider();return (await n({method:"eth_accounts"})).map(getAddress$1)},async getChainId(){let{request:n}=await this.getProvider(),s=await n({method:"eth_chainId"});return fromHex(s,"number")},async isAuthorized(){return e?!!(await this.getAccounts()).length:false},async switchChain({chainId:n}){let s=a.chains.find(h=>h.id===n);if(!s)throw new SwitchChainError(new ChainNotConfiguredError);let{request:d}=await this.getProvider();return await d({method:"wallet_switchEthereumChain",params:[{chainId:numberToHex(n)}]}),s},onAccountsChanged(n){n.length===0?this.onDisconnect():a.emitter.emit("change",{accounts:n.map(getAddress$1)});},onChainChanged(n){let s=Number(n);a.emitter.emit("change",{chainId:s});},async onDisconnect(){a.emitter.emit("disconnect"),e=false,t=void 0;},async getProvider({chainId:n}={}){t=impersonatedHelpers?.getImpersonated()?[impersonatedHelpers.getImpersonated()||zeroAddress]:void 0;let d=(a.chains.find(i=>i.id===n)??a.chains[0]).rpcUrls.default.http[0];return custom({request:async({method:i,params:p})=>{if(i==="eth_chainId")return numberToHex(r);if(i==="eth_requestAccounts")return t;if(i==="eth_signTypedData_v4"&&o.signTypedDataError)throw typeof o.signTypedDataError=="boolean"?new UserRejectedRequestError(new Error("Failed to sign typed data.")):o.signTypedDataError;if(i==="wallet_switchEthereumChain"){if(o.switchChainError)throw typeof o.switchChainError=="boolean"?new UserRejectedRequestError(new Error("Failed to switch chain.")):o.switchChainError;r=fromHex(p[0].chainId,"number"),this.onChainChanged(r.toString());return}if(i==="personal_sign"){if(o.signMessageError)throw typeof o.signMessageError=="boolean"?new UserRejectedRequestError(new Error("Failed to sign message.")):o.signMessageError;i="eth_sign",p=[p[1],p[0]];}let m={method:i,params:p},{error:u,result:y}=await rpc.http(d,{body:m});if(u)throw new RpcRequestError({body:m,error:u,url:d});return y}})({retryCount:1})}}))}var Ae={allowedDomains:[/gnosis-safe.io$/,/app.safe.global$/,/metissafe.tech$/],debug:false};var Te=c=>c.reduce((o,e)=>{let r=e.id;return o[r]=http(),o},{});function Ne(c,o){let{wagmiConfig:e,siwe:r}=c,{activeConnection:t,disconnect:a,connectionError:n,updateActiveConnection:s}=o,d=()=>{r?.enabled&&!r?.isSignedIn&&r?.isRejected&&t&&a(t.connectorType);},h=p=>{if(t&&getAdapterFromConnectorType(t.connectorType)!==OrbitAdapter.EVM)return;if(p.length===0){t&&a(t.connectorType);return}let m=getConnection(e);if(t&&getAdapterFromConnectorType(t.connectorType)!==OrbitAdapter.EVM||!m||n)return;let u=m.connector,k={connectorType:u?`${OrbitAdapter.EVM}:${formatConnectorName(u.name)}`:t?.connectorType,address:m.address,chainId:m.chainId,rpcURL:m?.chain?.rpcUrls.default.http[0],isConnected:true};s(k);};return d(),watchConnections(e,{onChange:h})}export{b as checkIsWalletAddressContract,Te as createDefaultTransports,Ne as createEVMConnectionsWatcher,S as impersonated,Ae as safeSdkOptions,fe as satelliteEVMAdapter};
1
+ import {OrbitAdapter,getConnectorTypeFromName,formatConnectorName,isSafeApp,impersonatedHelpers,getAdapterFromConnectorType}from'@tuwaio/orbit-core';import {createViemClient,getAddress,getAvatar,getName,checkAndSwitchChain}from'@tuwaio/orbit-evm';import {getBytecode,getConnectors,switchConnection,getChains,getConnection,getBalance,disconnect,connect,createConnector,ChainNotConfiguredError,watchConnections}from'@wagmi/core';import {formatUnits,zeroAddress,custom,numberToHex,UserRejectedRequestError,fromHex,RpcRequestError,getAddress as getAddress$1,SwitchChainError,http}from'viem';import {mainnet}from'viem/chains';import {rpc}from'viem/utils';var g=new Map;async function b({config:c,address:o,chainId:e,chains:r}){if(g.has(o))return g.get(o);if(createViemClient(e,r)){let n=!!await getBytecode(c,{address:o});return g.set(o,n),n}else return false}function fe(c,o){if(!c)throw new Error("Satellite EVM adapter requires a wagmi config object.");return {key:OrbitAdapter.EVM,connect:async({connectorType:e,chainId:r})=>{let a=getConnectors(c).find(n=>getConnectorTypeFromName(OrbitAdapter.EVM,formatConnectorName(n.name))===e);if(!a)throw new Error("Cannot find connector with this wallet type");try{await connect(c,{connector:a,chainId:r}),o&&!isSafeApp&&formatConnectorName(a.name)!=="porto"&&formatConnectorName(a.name)!=="geminiwallet"&&formatConnectorName(a.name)!=="impersonatedwallet"&&await o();let n=getConnection(c);return {connectorType:e,address:n.address??zeroAddress,chainId:n.chainId??mainnet.id,rpcURL:n.chain?.rpcUrls.default.http[0]??mainnet.rpcUrls.default.http[0],isConnected:n.isConnected,isContractAddress:!1,icon:a?.icon?.trim(),connector:a}}catch(n){throw new Error(n instanceof Error?n.message:String(n))}},disconnect:async e=>{if(e&&e.isConnected)await disconnect(c,{connector:e?.connector});else {let r=getConnectors(c);await Promise.allSettled(r.map(async t=>{await disconnect(c,{connector:t});}));}},getConnectors:()=>{let e=getConnectors(c);return {adapter:OrbitAdapter.EVM,connectors:e.map(r=>r)}},checkAndSwitchNetwork:async e=>await checkAndSwitchChain(Number(e),c),getBalance:async(e,r)=>{let t=await getBalance(c,{address:e,chainId:Number(r)});return {value:formatUnits(t.value,t.decimals),symbol:t.symbol}},getExplorerUrl:e=>{let{chain:r}=getConnection(c),t=r?.blockExplorers?.default.url;return e?`${t}/${e}`:t},getName:e=>getName(e),getAvatar:e=>getAvatar(e),getAddress:e=>getAddress(e),checkIsContractAddress:async({address:e,chainId:r})=>{let t=getChains(c);return await b({config:c,address:e,chainId:r,chains:t})},getSafeConnectorChainId:async()=>{let r=getConnectors(c).find(t=>t.name==="Safe");if(r)return await r.getChainId()},switchConnection:async e=>{let t=getConnectors(c).find(a=>getConnectorTypeFromName(OrbitAdapter.EVM,formatConnectorName(a.name))===e);if(!t)throw new Error(`Cannot find connector with type: ${e}`);try{await switchConnection(c,{connector:t});}catch(a){throw new Error(`Failed to switch to connector ${e}: ${a instanceof Error?a.message:String(a)}`)}}}}S.type="impersonated";function S(c){let o=c.features??{},e=false,r,t;return createConnector(a=>({id:"impersonated",name:"Impersonated Connector",type:S.type,async setup(){r=a.chains[0].id;},async connect({chainId:n}={}){if(o.connectError)throw typeof o.connectError=="boolean"?new UserRejectedRequestError(new Error("Failed to connect.")):o.connectError;let{request:s}=await this.getProvider(),d=await s({method:"eth_requestAccounts"}),h=await this.getChainId();return n&&h!==n&&(h=(await this.switchChain({chainId:n})).id),e=true,{accounts:d,chainId:h}},async disconnect(){e=false,t=void 0;},async getAccounts(){if(!e)throw new Error("Not connected connector");let{request:n}=await this.getProvider();return (await n({method:"eth_accounts"})).map(getAddress$1)},async getChainId(){let{request:n}=await this.getProvider(),s=await n({method:"eth_chainId"});return fromHex(s,"number")},async isAuthorized(){return e?!!(await this.getAccounts()).length:false},async switchChain({chainId:n}){let s=a.chains.find(h=>h.id===n);if(!s)throw new SwitchChainError(new ChainNotConfiguredError);let{request:d}=await this.getProvider();return await d({method:"wallet_switchEthereumChain",params:[{chainId:numberToHex(n)}]}),s},onAccountsChanged(n){n.length===0?this.onDisconnect():a.emitter.emit("change",{accounts:n.map(getAddress$1)});},onChainChanged(n){let s=Number(n);a.emitter.emit("change",{chainId:s});},async onDisconnect(){a.emitter.emit("disconnect"),e=false,t=void 0;},async getProvider({chainId:n}={}){t=impersonatedHelpers?.getImpersonated()?[impersonatedHelpers.getImpersonated()||zeroAddress]:void 0;let d=(a.chains.find(i=>i.id===n)??a.chains[0]).rpcUrls.default.http[0];return custom({request:async({method:i,params:p})=>{if(i==="eth_chainId")return numberToHex(r);if(i==="eth_requestAccounts")return t;if(i==="eth_signTypedData_v4"&&o.signTypedDataError)throw typeof o.signTypedDataError=="boolean"?new UserRejectedRequestError(new Error("Failed to sign typed data.")):o.signTypedDataError;if(i==="wallet_switchEthereumChain"){if(o.switchChainError)throw typeof o.switchChainError=="boolean"?new UserRejectedRequestError(new Error("Failed to switch chain.")):o.switchChainError;r=fromHex(p[0].chainId,"number"),this.onChainChanged(r.toString());return}if(i==="personal_sign"){if(o.signMessageError)throw typeof o.signMessageError=="boolean"?new UserRejectedRequestError(new Error("Failed to sign message.")):o.signMessageError;i="eth_sign",p=[p[1],p[0]];}let m={method:i,params:p},{error:u,result:y}=await rpc.http(d,{body:m});if(u)throw new RpcRequestError({body:m,error:u,url:d});return y}})({retryCount:1})}}))}var Ae={allowedDomains:[/gnosis-safe.io$/,/app.safe.global$/,/metissafe.tech$/],debug:false};var Te=c=>c.reduce((o,e)=>{let r=e.id;return o[r]=http(),o},{});function Ne(c,o){let{wagmiConfig:e,siwe:r}=c,{activeConnection:t,disconnect:a,connectionError:n,updateActiveConnection:s}=o,d=()=>{r?.enabled&&!r?.isSignedIn&&r?.isRejected&&t&&a(t.connectorType);},h=p=>{if(t&&getAdapterFromConnectorType(t.connectorType)!==OrbitAdapter.EVM)return;if(p.length===0){t&&a(t.connectorType);return}let m=getConnection(e);if(t&&getAdapterFromConnectorType(t.connectorType)!==OrbitAdapter.EVM||!m||n)return;let u=m.connector,k={connectorType:u?`${OrbitAdapter.EVM}:${formatConnectorName(u.name)}`:t?.connectorType,address:m.address,chainId:m.chainId,rpcURL:m?.chain?.rpcUrls.default.http[0],isConnected:true};s(k);};return d(),watchConnections(e,{onChange:h})}export{b as checkIsWalletAddressContract,Te as createDefaultTransports,Ne as createEVMConnectionsWatcher,S as impersonated,Ae as safeSdkOptions,fe as satelliteEVMAdapter};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuwaio/satellite-evm",
3
- "version": "1.0.0-fix-watcher-alpha.3.b979b45",
3
+ "version": "1.0.0-fix-error-handling-alpha.2.5165cfe",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
@@ -48,17 +48,17 @@
48
48
  "@tuwaio/satellite-core": ">=0.2.1"
49
49
  },
50
50
  "devDependencies": {
51
- "@wagmi/core": "^3.1.0",
52
- "@tuwaio/orbit-core": "^0.2.2",
53
- "@tuwaio/orbit-evm": "^0.2.5",
51
+ "@wagmi/core": "^3.3.1",
52
+ "@tuwaio/orbit-core": "^0.2.5",
53
+ "@tuwaio/orbit-evm": "^0.2.8",
54
54
  "immer": "^11.1.3",
55
55
  "jsdom": "^27.4.0",
56
56
  "tsup": "^8.5.1",
57
57
  "typescript": "^5.9.3",
58
- "viem": "^2.43.5",
59
- "vitest": "^4.0.16",
60
- "zustand": "^5.0.9",
61
- "@tuwaio/satellite-core": "^1.0.0-fix-watcher-alpha.3.b979b45"
58
+ "viem": "^2.45.0",
59
+ "vitest": "^4.0.18",
60
+ "zustand": "^5.0.10",
61
+ "@tuwaio/satellite-core": "^1.0.0-fix-error-handling-alpha.2.5165cfe"
62
62
  },
63
63
  "scripts": {
64
64
  "start": "tsup src/index.ts --watch",