@tuwaio/satellite-evm
@tuwaio/satellite-evm is the EVM Layer 4 (L4) package of Satellite Connect, the wallet connection project of TUWA Stage 2 (“State & Connection”, next to Pulsar). Built on @wagmi/core, viem and @tuwaio/orbit-evm, it provides the EVM adapter for @tuwaio/satellite-core, a watcher that keeps the store in sync with wagmi, and helpers for your wagmi config: default transports, Safe connector options and a connector that impersonates any address for testing. It does not use ethers.js or web3.js.
🏛️ Core Capabilities
- Adapter:
satelliteEVMAdapter(wagmiConfig, chains)connects the connectors of your wagmi config (injected wallets found through EIP-6963, WalletConnect, Safe, Coinbase…) by connector type, such as"evm:metamask". It asks the wallet to switch chains, reads native balances, builds block explorer links (undefinedwhen the chain has no explorer), resolves ENS names and avatars on Ethereum Mainnet, and checks whether the account is a smart contract. - Restore without a prompt: after a page load the store restores the last wallet with the adapter’s
reconnect: a wallet that still authorizes the site (eth_accountsof an injected wallet) is connected again without a prompt, on the chain it was saved with; a locked wallet, or one in which the site was disconnected, is left alone until the user connects it. A wallet that wagmi already holds in the page (connected through an earlier store on the same config, or restored byWagmiProvider) is taken over without a prompt, on restore and onconnect; any other wallet shows its connect prompt when the user picks it (wagmi asks injected wallets forwallet_requestPermissions, which shows MetaMask’s account picker). Disconnecting without a connection closes only the live wagmi connections that the adapter opened, never a connector without a connection or a connection opened by other code: wagmi’s injected connector sendswallet_revokePermissionson every disconnect, and MetaMask revokes the site’s permission for every tab of the origin. - Watcher:
createEVMConnectionsWatchersubscribes to wagmi’swatchConnectionsand copies account and chain changes made in the wallet into the store; it disconnects the store when the wallet disconnects. With a SIWX session it also disconnects when the sign-in is rejected or fails, or when the wallet switches to another account or chain than the session. Pass the store’sgetState, and the watcher reads the current state on every event. React apps useEVMConnectorsWatcherfrom@tuwaio/satellite-react/evminstead. - Contract accounts:
checkIsWalletAddressContractreads the account’s code on the requested chain and caches the result in memory per chain and address. - wagmi config helpers:
createDefaultTransports(chains)creates anhttp()transport for every chain;safeSdkOptionsare the options for thesafeconnector of@wagmi/connectors, with anchored Safe{Wallet} origins;impersonated()is a development connector that acts as a wallet for the address saved inlocalStorageand forwards requests to your node.
💾 Installation
pnpm add @tuwaio/satellite-evm @tuwaio/satellite-core @tuwaio/orbit-core @tuwaio/orbit-evm @wagmi/core viem zustand immer[!IMPORTANT]
@tuwaio/satellite-core(>=0.7),@tuwaio/orbit-core(>=0.5),@tuwaio/orbit-evm(>=0.3),@wagmi/core(3.x) andviem(2.x) are peer dependencies and must be installed alongside@tuwaio/satellite-evm.zustandandimmerare the peer dependencies of@tuwaio/satellite-core. Add@wagmi/connectorsif you use thesafe,walletConnectorcoinbaseWalletconnectors.
🚀 Usage
import { createDefaultTransports, impersonated, safeSdkOptions, satelliteEVMAdapter } from '@tuwaio/satellite-evm';
import { safe } from '@wagmi/connectors';
import { createConfig, injected } from '@wagmi/core';
import { mainnet, sepolia } from 'viem/chains';
export const appChains = [mainnet, sepolia] as const;
export const wagmiConfig = createConfig({
chains: appChains,
connectors: [injected(), safe({ ...safeSdkOptions }), impersonated({})],
transports: createDefaultTransports(appChains), // public RPC URLs: pass your own http(url) transports in production
ssr: true,
});
export const evmAdapter = satelliteEVMAdapter(wagmiConfig, appChains);Pass evmAdapter to createSatelliteConnectStore from @tuwaio/satellite-core or to SatelliteConnectProvider from @tuwaio/satellite-react, and run the watcher next to it. The complete React setup is on the @tuwaio/satellite-react page; the watcher without React is shown on the createEVMConnectionsWatcher page.
ssr: true (for Next.js and other server rendering) postpones the hydration of the wagmi config, and until it is hydrated, wagmi does not add the installed wallets found through EIP-6963 (MetaMask, Rabby…) to its connectors. EVMConnectorsWatcher from @tuwaio/satellite-react/evm hydrates the config after mount, so a React app needs no WagmiProvider from wagmi. Without React, call hydrate(wagmiConfig, { reconnectOnMount: false }).onMount() from @wagmi/core once in the browser, or create the config without ssr: true. The adapter’s watchConnectors reports every change of the connectors of the config (wagmi’s watchConnectors), so a wallet list that follows the store’s watchConnectors fills in when wagmi adds these wallets, also when it was opened before.
🗄️ Browser Storage
The package writes nothing to localStorage. The impersonated connector reads satellite-connect:impersonatedAddress (set with impersonatedHelpers.setImpersonated from @tuwaio/orbit-core, for example by Nova Connect) on every request; @tuwaio/satellite-core removes the key on initializeAutoConnect, on disconnectAll and when the last connection is disconnected. The keys that the store writes for EVM connections are listed on the @tuwaio/satellite-core page. wagmi keeps its own state in the storage of your wagmi config.
🌐 External Services
| Helper | Host | Purpose |
|---|---|---|
Adapter getBalance, checkIsWalletAddressContract | The wagmi transport of the chain | eth_getBalance, eth_getCode |
Adapter getName, getAvatar, getAddress | The default RPC URL of mainnet in your chains (viem’s mainnet definition when it is missing), not your wagmi transports | ENS resolution on Ethereum Mainnet |
Adapter getAvatar | The URL in the ENS avatar record, ipfs.io or arweave.net for IPFS and Arweave avatars | Avatar metadata (viem’s getEnsAvatar) |
createDefaultTransports | The default RPC URL of each chain definition | Every RPC request of the wagmi config |
impersonated | The default RPC URL of the chain | Every request except accounts and chain switching, including signing |
The default RPC URLs of the chain definitions are public and rate-limited. Explorer links point to the blockExplorers of the chain definitions and are not requested by the package.
📚 API Reference
Every export, with signatures and types generated from the source, is documented at satellite.docs.tuwa.io/packages/satellite-evm .
📄 License
Licensed under the Apache-2.0 License. See the LICENSE file for details.