💻 Développement

dev-web3-dapp-builder

Développement d'applications décentralisées (dApps) Web3.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- dev-web3-dapp-builder --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } dev-web3-dapp-builder -Launch"

🚀 Déjà installé ?

claude "/dev-web3-dapp-builder"

Ou tapez /dev-web3-dapp-builder dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

dAppWeb3blockchain appethers.jswagmiHardhatFoundryMetaMaskwallet connect

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/dev-web3-dapp-builder ~/.claude/skills/

Payload du plugin : skills/dev-web3-dapp-builder · source éditable : dev-skills/web3-dapp-builder

📖 Manuel

Web3 dApp Builder

Critères de décision : stack recommandée (2026)

BesoinRecommandation
Smart contracts SolidityFoundry (tests rapides, fork mainnet natif)
Scripts de déploiement complexesHardhat + hardhat-deploy ou Foundry script/
Frontend walletwagmi v2 + viem (remplace ethers.js v5)
Multi-walletRainbowKit ou ConnectKit sur WalletConnect v2
Indexation événementsThe Graph (subgraph) ou Ponder (self-hosted, TypeScript)
Monitoring/alertesOpenZeppelin Defender 2.0 ou Tenderly
Chaîne L2Base, Arbitrum, Optimism selon volume/coût gas
Account AbstractionERC-4337 + Pimlico/Biconomy Bundler

Workflow en étapes

1. Initialiser le projet

# Monorepo recommandé (contracts + frontend séparés)
mkdir my-dapp && cd my-dapp
pnpm init

# Foundry pour les contracts
forge init contracts --no-git
cd contracts && forge install OpenZeppelin/openzeppelin-contracts

# Frontend Next.js + wagmi
pnpm create next-app frontend --typescript
cd frontend
pnpm add wagmi viem @tanstack/react-query
pnpm add @rainbow-me/rainbowkit

Fichier wagmi.config.ts minimal :

import { http, createConfig } from 'wagmi'
import { mainnet, sepolia, base } from 'wagmi/chains'

export const config = createConfig({
  chains: [mainnet, sepolia, base],
  transports: {
    [mainnet.id]: http(process.env.NEXT_PUBLIC_ALCHEMY_MAINNET),
    [sepolia.id]: http(process.env.NEXT_PUBLIC_ALCHEMY_SEPOLIA),
    [base.id]: http(process.env.NEXT_PUBLIC_ALCHEMY_BASE),
  },
})

2. Développer les smart contracts

Structure Foundry recommandée :

contracts/
├── src/
│   └── MyToken.sol
├── script/
│   └── Deploy.s.sol
├── test/
│   └── MyToken.t.sol
└── foundry.toml

Snippet Deploy.s.sol :

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

import {Script} from "forge-std/Script.sol";
import {MyToken} from "../src/MyToken.sol";

contract DeployScript is Script {
    function run() external returns (MyToken) {
        uint256 deployerKey = vm.envUint("PRIVATE_KEY");
        vm.startBroadcast(deployerKey);
        MyToken token = new MyToken(msg.sender);
        vm.stopBroadcast();
        return token;
    }
}
# Déploiement sur Sepolia
forge script script/Deploy.s.sol --rpc-url $SEPOLIA_RPC --broadcast --verify

3. Générer et consommer l'ABI côté frontend

# Copie ABI automatique après build
forge build
cp out/MyToken.sol/MyToken.json ../frontend/src/abi/

Hook wagmi typé (useReadContract) :

import { useReadContract, useWriteContract } from 'wagmi'
import { MyTokenABI } from '@/abi/MyToken.json'

const TOKEN_ADDRESS = '0x...' as const

// Lecture
export function useTokenBalance(address: `0x${string}`) {
  return useReadContract({
    address: TOKEN_ADDRESS,
    abi: MyTokenABI,
    functionName: 'balanceOf',
    args: [address],
  })
}

// Écriture avec gestion d'état complète
export function useTransfer() {
  const { writeContract, isPending, isSuccess, error } = useWriteContract()

  function transfer(to: `0x${string}`, amount: bigint) {
    writeContract({
      address: TOKEN_ADDRESS,
      abi: MyTokenABI,
      functionName: 'transfer',
      args: [to, amount],
    })
  }

  return { transfer, isPending, isSuccess, error }
}

4. Wallet integration (RainbowKit)

// app/providers.tsx
'use client'
import { RainbowKitProvider } from '@rainbow-me/rainbowkit'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { config } from '@/wagmi.config'
import '@rainbow-me/rainbowkit/styles.css'

const queryClient = new QueryClient()

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <RainbowKitProvider>{children}</RainbowKitProvider>
      </QueryClientProvider>
    </WagmiProvider>
  )
}

Gestion du réseau incorrect :

import { useSwitchChain, useChainId } from 'wagmi'
import { base } from 'wagmi/chains'

function NetworkGuard({ children }) {
  const chainId = useChainId()
  const { switchChain } = useSwitchChain()

  if (chainId !== base.id) {
    return (
      <button onClick={() => switchChain({ chainId: base.id })}>
        Switch to Base
      </button>
    )
  }
  return children
}

5. Indexation avec The Graph (subgraph)

graph init --studio my-subgraph

schema.graphql minimal :

type Transfer @entity(immutable: true) {
  id: Bytes!
  from: Bytes!
  to: Bytes!
  value: BigInt!
  blockTimestamp: BigInt!
}

Query côté frontend :

const TRANSFERS_QUERY = `{
  transfers(first: 20, orderBy: blockTimestamp, orderDirection: desc) {
    id from to value blockTimestamp
  }
}`

const { data } = await fetch(SUBGRAPH_URL, {
  method: 'POST',
  body: JSON.stringify({ query: TRANSFERS_QUERY }),
}).then(r => r.json())

6. Tests Foundry

// test/MyToken.t.sol
contract MyTokenTest is Test {
    MyToken token;
    address alice = makeAddr("alice");

    function setUp() public {
        token = new MyToken(address(this));
        token.transfer(alice, 100e18);
    }

    // Fork test mainnet
    function testFork_SwapOnUniswap() public {
        vm.createSelectFork(vm.envString("MAINNET_RPC"), 19_000_000);
        // ... interactions avec Uniswap réel
    }

    function test_transferFailsWithoutBalance() public {
        vm.prank(alice);
        vm.expectRevert();
        token.transfer(address(this), 999e18);
    }
}
forge test -vvv
forge coverage --report lcov

7. Déploiement multi-chaîne

Fichier deploy.sh :

#!/bin/bash
CHAINS=("mainnet" "base" "arbitrum")
for chain in "${CHAINS[@]}"; do
  forge script script/Deploy.s.sol \
    --rpc-url $(eval echo \$${chain^^}_RPC) \
    --broadcast --verify \
    --etherscan-api-key $(eval echo \$${chain^^}_ETHERSCAN_KEY)
done

Sécurité — garde-fous obligatoires

RisqueMesure
ReentrancyReentrancyGuard d'OpenZeppelin sur toutes les fonctions external qui transfèrent de l'ETH
OverflowSolidity ≥ 0.8 (built-in checks) ; éviter unchecked sauf optimisation validée
Access controlOwnable2Step (OZ) — éviter Ownable simple (transfert en 2 étapes)
Signature replayInclure chainId + nonce dans EIP-712 domain separator
Oracle manipulationNe pas utiliser block.timestamp comme source de randomness ; utiliser Chainlink VRF
Proxy storage collisionUUPS : toujours héritage via UUPSUpgradeable, pas de constructeur, initializer protégé
Front-runningCommit-reveal ou slippage tolerance explicite sur les swaps
Private key leakJamais de clé privée dans .env commité ; utiliser --ledger en mainnet

Anti-patterns fréquents


Bonnes pratiques 2026