> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spire.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect Users

> Configure wallets for Pylon appchains and integrate wallet connections in applications

export function addNetwork(rpcUrl, chainId, chainName, currencySymbol = 'ETH', currencyName = 'Ethereum', decimals = 18) {
  if (typeof window.ethereum !== 'undefined') {
    const chainIdHex = '0x' + chainId.toString(16);
    window.ethereum.request({
      method: 'wallet_addEthereumChain',
      params: [{
        chainId: chainIdHex,
        chainName: chainName,
        nativeCurrency: {
          name: currencyName,
          symbol: currencySymbol,
          decimals: decimals
        },
        rpcUrls: [rpcUrl],
        blockExplorerUrls: []
      }]
    }).catch(error => {
      console.error('Error adding network:', error);
      alert(`Error adding network: ${error.message}`);
    });
  } else {
    alert('Wallet not detected. Please install a wallet to add the network.');
  }
}

export const CustomRPCAdder = () => {
  const [rpcUrl, setRpcUrl] = useState('');
  const [chainId, setChainId] = useState('');
  const [chainName, setChainName] = useState('');
  const [currencySymbol, setCurrencySymbol] = useState('');
  const [currencyName, setCurrencyName] = useState('');
  const [error, setError] = useState('');
  const codeGroupRef = useRef(null);
  const originalTemplatesRef = useRef(new Map());
  const handleAddNetwork = () => {
    if (!rpcUrl || !chainId || !chainName) {
      setError('RPC URL, Chain ID, and Chain Name are required');
      return;
    }
    addNetwork(rpcUrl, parseInt(chainId), chainName, currencySymbol, currencyName, 18);
  };
  useEffect(() => {
    const styleId = 'wallet-setup-codegroup-styles';
    if (!document.getElementById(styleId)) {
      const style = document.createElement('style');
      style.id = styleId;
      style.textContent = `
        /* Limit CodeGroup code block height to ~12 lines */
        [data-wallet-setup-codegroup] pre {
          max-height: 18rem !important;
          overflow-y: auto !important;
        }
        [data-wallet-setup-codegroup] code {
          max-height: 18rem !important;
          overflow-y: auto !important;
          display: block !important;
        }
      `;
      document.head.appendChild(style);
    }
  }, []);
  useEffect(() => {
    const updateCodeGroup = () => {
      const componentContainer = codeGroupRef.current?.closest('div')?.parentElement;
      if (!componentContainer) return;
      const allCodeBlocks = document.querySelectorAll('code');
      const targetCodeBlocks = Array.from(allCodeBlocks).filter(code => {
        const text = code.textContent || '';
        return text.includes('{CHAIN_ID_HEX}') || text.includes('{RPC_URL}') || text.includes('{CHAIN_NAME}') || text.includes('{CURRENCY_NAME}') || text.includes('{CURRENCY_SYMBOL}') || originalTemplatesRef.current.has(code);
      });
      if (targetCodeBlocks.length === 0) return;
      const firstCodeBlock = targetCodeBlocks[0];
      let codeGroupContainer = firstCodeBlock.closest('div[class*="codegroup"]') || firstCodeBlock.closest('div[class*="CodeGroup"]') || firstCodeBlock.closest('pre')?.parentElement?.parentElement;
      if (codeGroupContainer) {
        codeGroupContainer.setAttribute('data-wallet-setup-codegroup', 'true');
      }
      const chainIdHex = rpcUrl && chainId ? '0x' + parseInt(chainId).toString(16) : '{CHAIN_ID_HEX}';
      const finalChainName = chainName.trim() || '{CHAIN_NAME}';
      const finalRpcUrl = rpcUrl.trim() || '{RPC_URL}';
      const finalCurrencyName = currencyName.trim() || '{CURRENCY_NAME}';
      const finalCurrencySymbol = currencySymbol.trim() || '{CURRENCY_SYMBOL}';
      const escapeReplacement = str => {
        if (!str || typeof str !== 'string') return str;
        return str.replace(/\$/g, '$$$$');
      };
      targetCodeBlocks.forEach(codeBlock => {
        const currentContent = codeBlock.textContent || '';
        if (!originalTemplatesRef.current.has(codeBlock)) {
          const hasAllPlaceholders = currentContent.includes('{CHAIN_ID_HEX}') && currentContent.includes('{CHAIN_NAME}') && currentContent.includes('{RPC_URL}') && currentContent.includes('{CURRENCY_NAME}') && currentContent.includes('{CURRENCY_SYMBOL}');
          if (hasAllPlaceholders) {
            originalTemplatesRef.current.set(codeBlock, currentContent);
          } else {
            return;
          }
        }
        const originalTemplate = originalTemplatesRef.current.get(codeBlock);
        if (!originalTemplate) return;
        let content = String(originalTemplate);
        const replacements = {
          CHAIN_ID_HEX: String(escapeReplacement(chainIdHex)),
          CHAIN_NAME: String(escapeReplacement(finalChainName)),
          RPC_URL: String(escapeReplacement(finalRpcUrl)),
          CURRENCY_NAME: String(escapeReplacement(finalCurrencyName)),
          CURRENCY_SYMBOL: String(escapeReplacement(finalCurrencySymbol))
        };
        content = content.replace(/{CHAIN_ID_HEX}/g, replacements.CHAIN_ID_HEX);
        content = content.replace(/{CHAIN_NAME}/g, replacements.CHAIN_NAME);
        content = content.replace(/{RPC_URL}/g, replacements.RPC_URL);
        content = content.replace(/{CURRENCY_NAME}/g, replacements.CURRENCY_NAME);
        content = content.replace(/{CURRENCY_SYMBOL}/g, replacements.CURRENCY_SYMBOL);
        if (codeBlock.textContent !== content) {
          codeBlock.textContent = content;
        }
        const preElement = codeBlock.closest('pre');
        if (preElement) {
          preElement.setAttribute('data-wallet-setup-codegroup', 'true');
        }
      });
    };
    const timeoutId = setTimeout(updateCodeGroup, 100);
    const observer = new MutationObserver(() => {
      updateCodeGroup();
    });
    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
    return () => {
      clearTimeout(timeoutId);
      observer.disconnect();
    };
  }, [rpcUrl, chainId, chainName, currencySymbol, currencyName]);
  return <div ref={codeGroupRef} style={{
    marginTop: '2rem',
    padding: '1.5rem',
    border: '1px solid #e0e0e0',
    borderRadius: '8px'
  }}>
      <h3 style={{
    marginTop: 0
  }}>Add Custom Network</h3>
      <p>Enter your RPC URL and network details to generate embeddable code for your website.</p>
      
      <div style={{
    marginTop: '1.5rem'
  }}>
        <label style={{
    display: 'block',
    marginBottom: '0.5rem',
    fontWeight: 'bold'
  }}>
          RPC URL:
        </label>
        <input type="text" value={rpcUrl} onChange={e => setRpcUrl(e.target.value)} placeholder="https://pylon.{settlement-layer}.spire.dev/v1/chain/{chain-id}/rpc" style={{
    width: '100%',
    padding: '0.5rem',
    border: '1px solid #ccc',
    borderRadius: '4px',
    fontFamily: 'monospace',
    fontSize: '0.9rem'
  }} />
      </div>

      {error && <div style={{
    marginTop: '1rem',
    padding: '0.5rem',
    backgroundColor: '#fee',
    color: '#c33',
    borderRadius: '4px'
  }}>
          {error}
        </div>}

      <div style={{
    marginTop: '1.5rem',
    display: 'grid',
    gridTemplateColumns: '1fr 1fr',
    gap: '1rem'
  }}>
        <div>
          <label style={{
    display: 'block',
    marginBottom: '0.5rem',
    fontWeight: 'bold'
  }}>
            Chain ID:
          </label>
          <input type="text" value={chainId} onChange={e => setChainId(e.target.value)} placeholder="2137" style={{
    width: '100%',
    padding: '0.5rem',
    border: '1px solid #ccc',
    borderRadius: '4px'
  }} />
        </div>

        <div>
          <label style={{
    display: 'block',
    marginBottom: '0.5rem',
    fontWeight: 'bold'
  }}>
            Chain Name:
          </label>
          <input type="text" value={chainName} onChange={e => setChainName(e.target.value)} placeholder="My Custom Network" style={{
    width: '100%',
    padding: '0.5rem',
    border: '1px solid #ccc',
    borderRadius: '4px'
  }} />
        </div>

        <div>
          <label style={{
    display: 'block',
    marginBottom: '0.5rem',
    fontWeight: 'bold'
  }}>
            Currency Symbol:
          </label>
          <input type="text" value={currencySymbol} onChange={e => setCurrencySymbol(e.target.value)} placeholder="{CURRENCY_SYMBOL}" style={{
    width: '100%',
    padding: '0.5rem',
    border: '1px solid #ccc',
    borderRadius: '4px'
  }} />
        </div>

        <div>
          <label style={{
    display: 'block',
    marginBottom: '0.5rem',
    fontWeight: 'bold'
  }}>
            Currency Name:
          </label>
          <input type="text" value={currencyName} onChange={e => setCurrencyName(e.target.value)} placeholder="{CURRENCY_NAME}" style={{
    width: '100%',
    padding: '0.5rem',
    border: '1px solid #ccc',
    borderRadius: '4px'
  }} />
        </div>
      </div>

      <div style={{
    marginTop: '1.5rem'
  }}>
        <button onClick={handleAddNetwork} disabled={!rpcUrl || !chainId || !chainName} style={{
    padding: '0.75rem 1.5rem',
    backgroundColor: '#0073b7',
    color: 'white',
    border: 'none',
    borderRadius: '4px',
    cursor: !rpcUrl || !chainId || !chainName ? 'not-allowed' : 'pointer',
    opacity: !rpcUrl || !chainId || !chainName ? 0.6 : 1,
    fontSize: '1rem',
    fontWeight: 'bold'
  }}>
          Add Network to Wallet
        </button>
      </div>
    </div>;
};

Enable users to connect wallets to Pylon appchains and interact with applications. This page covers adding networks to wallets and integrating wallet connections in frontend applications.

## Available Test Networks

These test networks demonstrate Pylon functionality. Add them to a wallet with one click to test cross-chain operations and explore Pylon's features.

| Network                   | Settlement Layer | RPC URL                                                      | Chain ID | Add to Wallet                                                                                                                                                                                                                                                                                         |
| ------------------------- | ---------------- | ------------------------------------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Pylon Base Mainnet (Test) | Base Mainnet     | `https://pylon.base-mainnet.spire.dev/v1/chain/7312/rpc`     | `7312`   | <button onClick={() => addNetwork('https://pylon.base-mainnet.spire.dev/v1/chain/7312/rpc', 7312, 'Pylon Base Mainnet (Test)')} style={{background: '#0073b7', color: 'white', border: 'none', padding: '8px 16px', borderRadius: '5px', cursor: 'pointer'}}>Add Network</button>                     |
| Pylon Optimism Sepolia    | Optimism Sepolia | `https://pylon.optimism-sepolia.spire.dev/v1/chain/2138/rpc` | `2138`   | <button onClick={() => addNetwork('https://pylon.optimism-sepolia.spire.dev/v1/chain/2138/rpc', 2138, 'Pylon Optimism Sepolia')} style={{background: '#0073b7', color: 'white', border: 'none', padding: '8px 16px', borderRadius: '5px', cursor: 'pointer'}}>Add Network</button>                    |
| Pylon Celo Mainnet (Test) | Celo Mainnet     | `https://pylon.celo-mainnet.spire.dev/v1/chain/2139/rpc`     | `2139`   | <button onClick={() => addNetwork('https://pylon.celo-mainnet.spire.dev/v1/chain/2139/rpc', 2139, 'Pylon Celo Mainnet (Test)', 'CELO', 'Celo', 18)} style={{background: '#0073b7', color: 'white', border: 'none', padding: '8px 16px', borderRadius: '5px', cursor: 'pointer'}}>Add Network</button> |

## Add Your Custom Network

After setting up a Pylon appchain through [chain setup](/pylon/chain-setup), use the tool below to add it to a wallet or generate embeddable code for an application. The interactive form generates code snippets that update automatically as network details are entered.

<CustomRPCAdder />

## Copy-Paste Code for Your Website

Enter network details in the form above to generate code for adding a network to user wallets. The code snippets below update automatically with entered values.

<CodeGroup>
  ```html HTML Button theme={null}
  <button id="addNetworkBtn" onclick="addNetwork()">Add Network to Wallet</button>

  <script>
  async function addNetwork() {
      if (typeof window.ethereum !== 'undefined') {
          try {
              await window.ethereum.request({
                  method: 'wallet_addEthereumChain',
                  params: [{
                      chainId: '{CHAIN_ID_HEX}',
                      chainName: '{CHAIN_NAME}',
                      nativeCurrency: {
                          name: '{CURRENCY_NAME}',
                          symbol: '{CURRENCY_SYMBOL}',
                          decimals: 18
                      },
                      rpcUrls: ['{RPC_URL}'],
                      blockExplorerUrls: []
                  }]
              });
              alert('Network added successfully!');
          } catch (error) {
              console.error('Error adding network:', error);
              alert('Error adding network: ' + error.message);
          }
      } else {
          alert('Wallet not detected. Please install MetaMask or another compatible wallet.');
      }
  }
  </script>

  <style>
  #addNetworkBtn {
      background-color: #0073b7;
      color: white;
      border: none;
      padding: 12px 24px;
      border-radius: 6px;
      font-size: 16px;
      font-weight: 500;
      cursor: pointer;
      transition: background-color 0.2s ease;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
  }

  #addNetworkBtn:hover {
      background-color: #005a8f;
  }

  #addNetworkBtn:active {
      background-color: #004d7a;
  }
  </style>
  ```

  ```jsx React Component theme={null}
  import { useState } from 'react';

  function AddNetworkButton() {
      const [status, setStatus] = useState('');

      const addNetwork = async () => {
          if (typeof window.ethereum !== 'undefined') {
              try {
                  await window.ethereum.request({
                      method: 'wallet_addEthereumChain',
                      params: [{
                          chainId: '{CHAIN_ID_HEX}',
                          chainName: '{CHAIN_NAME}',
                          nativeCurrency: {
                              name: '{CURRENCY_NAME}',
                              symbol: '{CURRENCY_SYMBOL}',
                              decimals: 18
                          },
                          rpcUrls: ['{RPC_URL}'],
                          blockExplorerUrls: []
                      }]
                  });
                  setStatus('Network added successfully!');
              } catch (error) {
                  setStatus('Error: ' + error.message);
              }
          } else {
              setStatus('Please install a wallet');
          }
      };

      return (
          <div>
              <button 
                  onClick={addNetwork}
                  style={{
                      backgroundColor: '#0073b7',
                      color: 'white',
                      border: 'none',
                      padding: '12px 24px',
                      borderRadius: '6px',
                      fontSize: '16px',
                      fontWeight: 500,
                      cursor: 'pointer',
                      transition: 'background-color 0.2s ease',
                      fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif'
                  }}
                  onMouseEnter={(e) => e.target.style.backgroundColor = '#005a8f'}
                  onMouseLeave={(e) => e.target.style.backgroundColor = '#0073b7'}
              >
                  Add Network to Wallet
              </button>
              {status && <p style={{ marginTop: '12px', color: status.includes('Error') ? '#d32f2f' : '#2e7d32' }}>{status}</p>}
          </div>
      );
  }
  ```
</CodeGroup>

## Integrate Wallets in Your Application

For production applications, integrate wallet connections using established libraries and patterns. This provides better user experience, error handling, and support for multiple wallet types.

### Recommended Approach: wagmi

[wagmi](https://wagmi.sh) is a React Hooks library for Ethereum that provides a simple, type-safe way to connect wallets and interact with chains. It supports MetaMask, WalletConnect, Coinbase Wallet, and other injected wallets.

**Key benefits:**

* **Type-safe** - Full TypeScript support
* **Multi-wallet support** - Connect to multiple wallet providers
* **Auto-switching** - Automatically switch networks when needed
* **React hooks** - Simple, declarative API
* **Active maintenance** - Regularly updated with latest wallet standards

**Quick start:**

1. Review the [wagmi Getting Started guide](https://wagmi.sh/react/getting-started)
2. Configure your Pylon appchain as a custom chain in wagmi
3. Use hooks like `useConnect`, `useAccount`, and `useSwitchChain` to manage wallet connections

### Alternative Libraries

* **[viem](https://viem.sh)** - TypeScript library for Ethereum, works well with wagmi or standalone
* **[ethers.js](https://docs.ethers.org/)** - Popular Ethereum library with wallet connection utilities
* **[web3.js](https://web3js.readthedocs.io/)** - Ethereum JavaScript API

For wallet-specific implementations, refer to official documentation:

* [MetaMask Provider API](https://docs.metamask.io/wallet/reference/provider-api/)
* [WalletConnect v2 Documentation](https://docs.walletconnect.com/)

### UX Best Practices

* **Automatic network switching** - Detect when users need to switch networks and prompt them
* **Clear error messages** - Handle network mismatches and connection failures gracefully
* **Loading states** - Show connection status during wallet interactions
* **Mobile support** - Consider WalletConnect for mobile wallet connections

## Next Steps

* **[Build Onchain →](/pylon/build-onchain)** - Deploy contracts and build applications
* **[Quickstart →](/pylon/quickstart)** - Deploy your first contract
* **[Chain Management →](/pylon/chain-management)** - Monitor transactions and activity
