> ## 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.

# Quickstart

> Deploy your first cross-chain contract in 10 minutes

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);
    });
  } else {
    alert('Wallet not detected. Please install a wallet to add the network.');
  }
}

## Deploy Your First Cross-Chain Contract

Get started with Pylon by deploying a contract on one of our demo appchains and read from their settlement layer.

### Prerequisites

* **Testnet ETH** - [Apply for testnet funding](https://www.spire.dev/contact) (tell us which network and provide your wallet address)
* **Foundry installed** - [Install from foundryup.rs](https://book.getfoundry.sh/getting-started/installation)

### Step 1: Create Your Project

```bash theme={null}
forge init my-pylon-app
cd my-pylon-app
```

### Step 2: Configure Your Network

Add to your `foundry.toml`:

```toml theme={null}
[rpc_endpoints]
pylon = "https://pylon.{settlement-layer}.spire.dev/v1/chain/{chain-id}/rpc"
```

**Available Networks:**

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

### Step 3: Make a Direct Cross-Chain Call

Let's start by understanding how cross-chain calls work. Pylon provides a **[Port Contract](/pylon/architecture#port-contracts)** that reads from the settlement layer.

Make a direct call to read WETH name from the settlement layer:

```bash theme={null}
cast call 0x0000000000000000000000000000000000000042 \
    "readSettlement(address,bytes)" \
    0x4200000000000000000000000000000000000006 \
    "$(cast calldata 'name()')" \
    --rpc-url pylon
```

**What happened:**

1. Called the SettlementPort contract at `0x0000000000000000000000000000000000000042`
2. Told it to call `name()` on WETH (`0x4200000000000000000000000000000000000006`)
3. The **[coordinator](/pylon/architecture#coordinator)** detected the cross-chain call, forwarded it to the settlement layer, and returned the result synchronously
4. The result is encoded as bytes

Since the return type for the settlement contract being called is known, just specify the return type and it will automatically decode the result:

```bash theme={null}
cast call 0x0000000000000000000000000000000000000042 \
    "readSettlement(address,bytes)(string)" \
    0x4200000000000000000000000000000000000006 \
    "$(cast calldata 'name()')" \
    --rpc-url pylon
```

This demonstrates **[synchronous composability](/pylon/synchronous-composability)** - you can read from the settlement layer as if it were on the same chain.

### Step 4: Create Forwarding Proxy (Better Developer Experience)

Making raw `readSettlement` calls works, but it's verbose. We can create a **[forwarding proxy](/pylon/architecture#forwarding-proxy-contracts)** that makes settlement layer contracts callable using standard interfaces like ERC20.

Create `src/SettlementForwardingProxy.sol`:

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

import {ISettlementReader} from "./ISettlementReader.sol";

contract SettlementForwardingProxy {
    address public immutable SETTLEMENT_PORT;
    address public immutable IMPL;
    
    constructor(address _settlementPort, address _impl) {
        SETTLEMENT_PORT = _settlementPort;
        IMPL = _impl;
    }
    
    fallback() external payable {
        bytes memory result = ISettlementReader(SETTLEMENT_PORT).readSettlement(IMPL, msg.data);
        assembly {
            let ptr := add(result, 0x20)
            let len := mload(result)
            return(ptr, len)
        }
    }
    
    receive() external payable {
        bytes memory result = ISettlementReader(SETTLEMENT_PORT).readSettlement(IMPL, bytes(""));
        assembly {
            let ptr := add(result, 0x20)
            let len := mload(result)
            return(ptr, len)
        }
    }
}
```

Create `src/ISettlementReader.sol`:

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

interface ISettlementReader {
    function readSettlement(address target, bytes calldata callData) external view returns (bytes memory);
}
```

Deploy the proxy (replace with your actual settlement port address):

```bash theme={null}
forge create src/SettlementForwardingProxy.sol:SettlementForwardingProxy \
    --rpc-url pylon \
    --broadcast \
    --private-key $PRIVATE_KEY \
    --constructor-args 0x0000000000000000000000000000000000000042 0x4200000000000000000000000000000000000006
```

Save the proxy address - you'll use it in the next step.

**What this proxy does:**

* Constructor takes two addresses: the **[SettlementPort](/pylon/architecture#port-contracts)** and a target contract (in this case WETH)
* `fallback()` captures any function call and forwards it to `readSettlement()`
* Returns the result as if the target contract were local
* This lets you call settlement layer contracts using standard interfaces

### Step 5: Create a Contract That Uses the Proxy

Now let's create a contract that demonstrates using the proxy with standard interfaces:

Create `src/ProxyCaller.sol`:

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

// Minimal ERC20 view interface for WETH
interface IERC20View {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
}

contract ProxyCaller {
    address public immutable PROXY;
    
    constructor(address _proxy) {
        PROXY = _proxy;
    }
    
    function nameViaProxy() external view returns (string memory) {
        return IERC20View(PROXY).name();
    }
    
    function symbolViaProxy() external view returns (string memory) {
        return IERC20View(PROXY).symbol();
    }
    
    function decimalsViaProxy() external view returns (uint8) {
        return IERC20View(PROXY).decimals();
    }
}
```

**How this works:**

* `ProxyCaller` calls standard ERC20 functions on the PROXY address
* The proxy's `fallback()` forwards these calls to **[SettlementPort](/pylon/architecture#port-contracts)**
* SettlementPort reads from the settlement layer synchronously via **[priming transactions](/pylon/architecture#priming-transactions)**
* Results return as if WETH were deployed on your appchain

### Step 6: Deploy Contracts

Deploy the ProxyCaller contract:

```bash theme={null}
forge create src/ProxyCaller.sol:ProxyCaller \
    --rpc-url pylon \
    --broadcast \
    --private-key $PRIVATE_KEY \
    --constructor-args <PROXY_ADDRESS>
```

Save the ProxyCaller address.

### Step 7: Test Your Cross-Chain Calls

```bash theme={null}
cast call <CALLER_ADDRESS> "nameViaProxy()(string)" \
    --rpc-url pylon

cast call <CALLER_ADDRESS> "symbolViaProxy()(string)" \
    --rpc-url pylon

cast call <CALLER_ADDRESS> "decimalsViaProxy()(uint8)" \
    --rpc-url pylon
```

Test getting WETH name, symbol, and decimals via the proxy.

These calls demonstrate how you can interact with settlement layer contracts using standard interfaces, just like they were on the same chain.

### What This Demonstrates

1. **Direct Pattern (Step 3):** Made raw `readSettlement` calls to **[SettlementPort](/pylon/architecture#port-contracts)**, showing the foundation of cross-chain reads
2. **Proxy Pattern (Step 4-5):** Created a **[forwarding proxy](/pylon/architecture#forwarding-proxy-contracts)** that enables standard interface calls to settlement layer contracts from your appchain contracts
3. **Developer Experience:** Now you can call settlement layer contracts using familiar Solidity syntax and interfaces

### How Cross-Chain Calls Flow Through Pylon

<img src="https://mintcdn.com/spire/Fpc2rAFPa-Jycg4_/images/pylon/how-cross-chain-calls-flow-through-pylon.png?fit=max&auto=format&n=Fpc2rAFPa-Jycg4_&q=85&s=ea02287675f75f328247d9f099fc6080" alt="How Cross-Chain Calls Flow Through Pylon" width="675" height="1200" data-path="images/pylon/how-cross-chain-calls-flow-through-pylon.png" />

The key insight is that Pylon's **[coordinator](/pylon/architecture#coordinator)** detects these cross-chain calls, forwards them to the settlement layer, captures the results, and makes them available synchronously through the **[Port Contract](/pylon/architecture#port-contracts)**. This is **[synchronous composability](/pylon/synchronous-composability)** in action.

## Next Steps

* **[Chain Setup →](/pylon/chain-setup)** - Configure your own based appchain development environment
* **[Build Onchain →](/pylon/build-onchain)** - Learn to deploy and test applications
* **[Architecture →](/pylon/architecture)** - Understand how it works
