Skip to content

Latest commit

 

History

History
299 lines (241 loc) · 9.03 KB

File metadata and controls

299 lines (241 loc) · 9.03 KB
section developers
date Last Modified
title Developer Quickstart
lang en
permalink developers/developer-quickstart
excerpt Scroll Developer Quickstart helps you acquire testnet Ether, configure your network, and access all of your favorite tooling
whatsnext
Verify Your Smart Contracts
/en/developers/verifying-smart-contracts

import Aside from "../../../../components/Aside.astro" import ClickToZoom from "../../../../components/ClickToZoom.astro" import networkSelection from "./_images/mmNetworkSelection.png" import injectedProviderMM from "./_images/injectedProviderMM.png" import ToggleElement from "../../../../components/ToggleElement.astro" import wagmiDemo from "../../../../assets/images/developers/getting-started/wagmi-demo.png"

Welcome to the Scroll Developer Quickstart. This guide walks you through building a minimal on-chain app, from installing tooling to deploying contracts on Scroll and connecting it to a React frontend.

What You'll Build

By the time you're done, you'll have:

  • Installed developer tooling.
  • Deployed a Counter smart contract on Scroll by using Foundry.
  • Created a React frontend (with wagmi and Viem) to read from and write to your contract.
_What you'll build: a hello world dApp on Scroll connecting a React frontend to a contract you deployed._

Why Scroll?

Scroll is a high performance, EVM equivalent zkEVM Layer 2 designed to help developers build secure, low-cost, and engaging applications. Because Scroll is fully bytecode compatible with the EVM, your existing development and testing tools work out of the box, just configure them to use a Scroll RPC provider.

If you run into any issues, please reach out in our Discord.

Install and Configure Foundry

We'll use Foundry to compile and deploy our Counter contract.

Create a folder for the contract:

# create a new contracts directory
mkdir contracts
cd contracts
# install and update foundry if you haven't
curl -L https://foundry.paradigm.xyz | bash
foundryup
# initialize a fresh Foundry project
forge init --no-git

Configure Environment Variables

To deploy your smart contracts on Scroll, you need two key components:

New to Web3? Start by installing [Rabby](https://rabby.io/) or [MetaMask](https://metamask.io/). After creating your wallet and securing your seed phrase, head over to [ChainList](https://chainlist.org/chain/534351) to add Scroll Sepolia to your wallet with a single click. Once you're set up, you can export your private key for deployment by following [MetaMask's guide](https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/).

Let's set up both of these:

.env

SCROLL_SEPOLIA_RPC_URL="https://sepolia-rpc.scroll.io/"
PRIVATE_KEY=<YOUR_PRIVATE_KEY>

Also be sure you don't upload this to a public repo by setting up a .gitignore.

.gitignore

.env

If you don't have Sepolia test ETH yet, join our Telegram faucet and send /drop YOUR_ADDRESS to receive Sepolia ETH on Scroll.

Never share or commit your private key. Always keep it secure and handle with care.

Deploy Your Smart Contract

With Foundry set up and .env in place, deploy the Counter contract.

In the contracts directory, run:

source .env
forge create src/Counter.sol:Counter \
  --rpc-url $SCROLL_SEPOLIA_RPC_URL \
  --broadcast \
  --private-key $PRIVATE_KEY

After deployment, you'll see something like:

[⠊] Compiling...
No files changed, compilation skipped
Deployer: 0xbef34f2FCAe62dC3404c3d01AF65a7784c9c4A19
Deployed to: 0xf0e9ceCAE516B2F5Ac297B3857453b07455f817F
Transaction hash: 0x2bca5934ad82ce26332847fdd6a9241b0da0e38e6928f06499ee58ebc967bbde

Copy the address under Deployed to:. You'll need it when configuring the frontend.

Create and Configure the React Frontend

We'll build a simple React app (using Vite, wagmi, and Viem) that connects to MetaMask (or another injected provider) and interacts with the Counter contract.

From the root of your project:

cd ..
pnpm create wagmi frontend -t vite-react
cd frontend
pnpm install

This scaffolds a new Vite + React + wagmi template.

Now add the smart contract address you just deployed to the .env.local file.

.env.local

VITE_COUNTER_CONTRACT_ADDRESS=0xYourNewContractAddress

Implement the Frontend Logic

Create a new Counter component on src/components/Counter.tsx that is able to read and write to our smart contract.

src/components/Counter.tsx

import { useAccount, useWriteContract } from 'wagmi'
import { createPublicClient, http } from 'viem'
import { scrollSepolia } from 'viem/chains'
import { useState, useEffect } from 'react'

const COUNTER_CONTRACT_ADDRESS = import.meta.env.VITE_COUNTER_CONTRACT_ADDRESS as `0x${string}`

// Connect your client to Scroll Sepolia
const publicClient = createPublicClient({
  chain: scrollSepolia,
  transport: http()
})

// Define the ABI so we can interact with the contract from TS
const counterABI = [
  {
    inputs: [],
    name: "increment",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
  {
    inputs: [],
    name: "number",
    outputs: [{ type: "uint256" }],
    stateMutability: "view",
    type: "function",
  },
] as const

// Custom hook for counter functionality
function useCounter() {
  const [number, setNumber] = useState<bigint | null>(null)
  const { writeContract, isPending: isIncrementing } = useWriteContract()
  const fetchNumber = async () => {
    try {
      const result = await publicClient.readContract({
        address: COUNTER_CONTRACT_ADDRESS,
        abi: counterABI,
        functionName: 'number',
      })
      setNumber(result)
    } catch (error) {
      console.error('Error reading contract:', error)
    }
  }
  useEffect(() => {
    fetchNumber()
  }, [])
  const increment = () => {
    writeContract({
      address: COUNTER_CONTRACT_ADDRESS,
      abi: counterABI,
      functionName: 'increment',
    }, {
      onSuccess: (txHash) => {
        publicClient.waitForTransactionReceipt({ hash: txHash })
          .then(() => fetchNumber())
          .catch(console.error)
      },
    })
  }
  return {
    number,
    isIncrementing,
    increment,
    refreshNumber: fetchNumber
  }
}
// Counter Component
export function Counter() {
  const account = useAccount()
  const { number, isIncrementing, increment } = useCounter()
  return (
    <div style={{ marginTop: '20px' }}>
      <h2>Counter</h2>
      <p>Current number: {number?.toString()}</p>
      {account.status === 'connected' && (
        <button
          onClick={increment}
          disabled={isIncrementing}
        >
          {isIncrementing ? 'Incrementing...' : 'Increment'}
        </button>
      )}
    </div>
  )
}

Now let's add our new component into src/App.tsx.

import { useAccount, useConnect, useDisconnect } from 'wagmi'
// Import our newly created component
import { Counter } from './components/Counter'

function App() {
  const account = useAccount()
  const { connectors, connect, error } = useConnect()
  const { disconnect } = useDisconnect()

  return (
    <div style={{ padding: '20px' }}>
      <div>
        <h2>Wallet</h2>
        {account.status === 'connected' ? (
          <>
            <p>Connected: {account.addresses?.[0]}</p>
            <button onClick={() => disconnect()}>Disconnect</button>
          </>
        ) : (
          <>
            {connectors.map((connector) => (
              <button
                key={connector.uid}
                onClick={() => connect({ connector })}
                style={{ marginRight: '10px' }}
              >
                Connect {connector.name}
              </button>
            ))}
            {error && <p style={{ color: 'red' }}>{error.message}</p>}
          </>
        )}
      </div>

      {/* Use the Counter component in our dApp */}
      <Counter />
    </div>
  )
}

export default App

Start the Frontend

Start your development server:

pnpm run dev

Open your browser at http://localhost:5173 or whatever Vite shows. You should see wallet connection buttons and an increment button. First, click the connect wallet button corresponding to the wallet you installed and then click the increment button to see the number going up.

Ready to go live?

When you’re ready to switch to mainnet, simply replace the Sepolia RPC URL with the Scroll mainnet RPC URL in your environment: https://rpc.scroll.io/. In your React code, update the Viem client to use scroll instead of scrollSepolia:

import { scroll } from 'viem/chains'

const publicClient = createPublicClient({
  chain: scroll,
  transport: http(),
})

This change tells Viem to point at the live Scroll chain rather than Sepolia. All of your existing contract reads and writes will now go to mainnet.