Wallet connection state machine.
The wallet is modeled as an explicit state — you can't accidentally
call a contract without a connected wallet because the compiler
won't give you an Address from a Disconnected state.
case model.wallet of
Connected info ->
-- info.address : T.Address — only available here
buy info.address amount
WrongChain _ _ ->
-- wallet is connected but on the wrong chain
button [ onClick SwitchChain ] [ text "Switch chain" ]
ReadOnly ->
-- rpcUrl configured but no wallet; reads work, writes will fail
viewReadOnlyBanner
_ ->
showConnectButtonEIP-6963 multi-wallet discovery — listen for WalletsDiscovered on the
port and present the list to the user; call selectWallet rdns when they pick.
Typical connection flow:
startConnect on state, send connect via port.WalletsDiscovered providers arrives → show picker if providers is non-empty.selectWallet rdns via port.WalletConnected addr chainId arrives → update transitions to Connected or WrongChain.WrongChain → send switchChain expectedChain via port.For native balance queries, use Web3.Balance. For adding chains, use addChain with
a ChainConfig record and follow up with switchChain.
Messages from the JS wallet port.
Commands to send to JS via port.
A wallet provider discovered via EIP-6963.
Configuration for adding a new chain to the wallet (EIP-3085).
Transition to Connecting state before sending the connect port command.
Call this when the user clicks the connect button, then send connect via the port:
( { model | wallet = Wallet.startConnect model.wallet }
, web3Cmd (Wallet.encode Wallet.connect)
)Valid transitions: Disconnected → Connecting, Error _ → Connecting.
All other states are unchanged (connecting while already connected is a no-op).
Command to request wallet disconnection.
Command to switch chain.
Command to select a specific wallet by its RDNS identifier (EIP-6963).
selectWallet "io.metamask"Request wallet_addEthereumChain (EIP-3085) to add a new network.
addChain
{ chainId = 369
, chainName = "PulseChain"
, rpcUrls = [ "https://rpc.pulsechain.com" ]
, nativeCurrency = { name = "Pulse", symbol = "PLS", decimals = 18 }
, blockExplorerUrls = [ "https://scan.pulsechain.com" ]
}Command to add a token to the wallet UI (EIP-747).
Command to request wallet permissions (EIP-2255).
Command to get current wallet permissions (EIP-2255).
True if the wallet is in the Connected state.
True if in ReadOnly mode (rpcUrl present, no wallet). Reads work; writes will fail.
Extract the connected address, if any.
Extract the connected chain ID, if any.
Wallet connection state. Every possible state is explicit.
Disconnected— no wallet detected, no rpcUrl configuredReadOnly— rpcUrl is present but no wallet; reads work, writes will failConnecting— wallet connection in progressConnected— wallet connected on the expected chainWrongChain— wallet connected but on the wrong chainError— unrecoverable error