Outils·7 min de lecture·Par Solingo

MetaMask pour Développeurs — Connectez votre dApp au Web3

MetaMask est le portefeuille Web3 le plus populaire avec plus de 30 millions d'utilisateurs. Apprenez à détecter, connecter et interagir avec MetaMask pour construire des expériences dApp fluides.

# MetaMask pour Développeurs — Connectez votre dApp au Web3

MetaMask est la porte d'entrée vers le Web3 pour des millions d'utilisateurs. En tant que portefeuille Ethereum le plus populaire en extension navigateur, il permet aux utilisateurs d'interagir avec des applications décentralisées (dApps) directement depuis leur navigateur. Pour les développeurs, l'intégration de MetaMask est essentielle pour permettre aux utilisateurs de connecter leurs portefeuilles, signer des transactions et interagir avec des smart contracts. Ce guide couvre tout ce que vous devez savoir pour construire une intégration MetaMask fluide.

Qu'est-ce que MetaMask ?

MetaMask est un portefeuille de cryptomonnaie et une passerelle vers les applications blockchain. Il fonctionne comme :

  • Extension navigateur (Chrome, Firefox, Edge, Brave)
  • Application mobile (iOS et Android)
  • Provider Web3 injectant window.ethereum dans les pages web
  • Gestionnaire de comptes pour les adresses Ethereum et clés privées
  • Sélecteur de réseau entre Ethereum mainnet, testnets et autres chaînes EVM

Avec plus de 30 millions d'utilisateurs actifs mensuels, MetaMask est le portefeuille par défaut pour la plupart des dApps Ethereum.

Comment fonctionne MetaMask

Lorsqu'il est installé, MetaMask injecte un objet JavaScript appelé window.ethereum (ou window.ethereum via EIP-6963) dans chaque page web. Votre dApp utilise cet objet pour :

  • Détecter si MetaMask est installé
  • Demander la permission de l'utilisateur pour se connecter
  • Lire l'adresse du compte connecté
  • Envoyer des demandes de transaction
  • Écouter les changements de compte/réseau
  • Toutes les opérations sensibles (signature de transactions, messages) se produisent dans l'interface sécurisée de MetaMask — votre dApp n'a jamais accès aux clés privées.

    Détecter MetaMask

    Détection basique

    if (typeof window.ethereum !== 'undefined') {
    

    console.log('MetaMask is installed!');

    } else {

    console.log('Please install MetaMask');

    // Rediriger vers https://metamask.io/download

    }

    EIP-6963 : Détection multi-portefeuilles

    Les dApps modernes devraient supporter plusieurs portefeuilles. EIP-6963 fournit une manière standard de détecter tous les portefeuilles installés :

    // Écouter les providers de portefeuilles
    

    const wallets = [];

    window.addEventListener('eip6963:announceProvider', (event) => {

    wallets.push(event.detail);

    });

    // Demander les annonces de portefeuilles

    window.dispatchEvent(new Event('eip6963:requestProvider'));

    // wallets contient maintenant tous les providers installés (MetaMask, Coinbase Wallet, etc.)

    Vérifier si MetaMask est le provider actif

    const isMetaMask = window.ethereum?.isMetaMask;
    

    if (isMetaMask) {

    console.log('MetaMask detected');

    }

    Se connecter à MetaMask

    Demander l'accès au compte

    async function connectWallet() {
    

    try {

    // Demander l'accès au compte

    const accounts = await window.ethereum.request({

    method: 'eth_requestAccounts'

    });

    const account = accounts[0];

    console.log('Connected account:', account);

    return account;

    } catch (error) {

    if (error.code === 4001) {

    // L'utilisateur a rejeté la demande

    console.log('Please connect to MetaMask');

    } else {

    console.error('Error connecting:', error);

    }

    }

    }

    Obtenir les comptes connectés (sans popup)

    Si l'utilisateur s'est déjà connecté, utilisez eth_accounts (n'affiche pas de popup) :

    async function getConnectedAccounts() {
    

    const accounts = await window.ethereum.request({

    method: 'eth_accounts'

    });

    return accounts; // Tableau vide si non connecté

    }

    Flux de connexion complet

    async function init() {
    

    // Vérifier si déjà connecté

    const accounts = await window.ethereum.request({ method: 'eth_accounts' });

    if (accounts.length > 0) {

    // Déjà connecté

    setAccount(accounts[0]);

    } else {

    // Afficher le bouton "Connect Wallet"

    document.getElementById('connectButton').addEventListener('click', async () => {

    const newAccounts = await window.ethereum.request({

    method: 'eth_requestAccounts'

    });

    setAccount(newAccounts[0]);

    });

    }

    }

    function setAccount(account) {

    document.getElementById('account').textContent = account;

    document.getElementById('connectButton').style.display = 'none';

    document.getElementById('dapp').style.display = 'block';

    }

    Envoyer des transactions

    Envoyer de l'ETH

    async function sendEther(to, amount) {
    

    const accounts = await window.ethereum.request({ method: 'eth_accounts' });

    const from = accounts[0];

    // montant en wei (1 ETH = 10^18 wei)

    const value = '0x' + (amount * 10**18).toString(16);

    try {

    const txHash = await window.ethereum.request({

    method: 'eth_sendTransaction',

    params: [{

    from: from,

    to: to,

    value: value,

    // gas: '0x5208', // Optionnel : 21000 wei pour un transfert simple

    }],

    });

    console.log('Transaction hash:', txHash);

    return txHash;

    } catch (error) {

    console.error('Transaction failed:', error);

    }

    }

    // Usage

    await sendEther('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', 0.1);

    Interagir avec des smart contracts (brut)

    async function callContractFunction() {
    

    const contractAddress = '0x...';

    const accounts = await window.ethereum.request({ method: 'eth_accounts' });

    // Signature de fonction : transfer(address,uint256)

    const functionSignature = '0xa9059cbb'; // Premiers 4 octets de keccak256("transfer(address,uint256)")

    // Encoder les paramètres (address + amount)

    const recipient = '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'.slice(2).padStart(64, '0');

    const amount = (100 * 10**18).toString(16).padStart(64, '0');

    const data = functionSignature + recipient + amount;

    const txHash = await window.ethereum.request({

    method: 'eth_sendTransaction',

    params: [{

    from: accounts[0],

    to: contractAddress,

    data: data,

    }],

    });

    return txHash;

    }

    Note : L'encodage manuel est sujet à erreurs. Utilisez ethers.js ou web3.js (voir ci-dessous).

    Changer de réseau

    Demander le changement de réseau

    async function switchToSepolia() {
    

    try {

    await window.ethereum.request({

    method: 'wallet_switchEthereumChain',

    params: [{ chainId: '0xaa36a7' }], // Testnet Sepolia

    });

    } catch (error) {

    if (error.code === 4902) {

    // Réseau non ajouté à MetaMask

    await addSepoliaNetwork();

    } else {

    console.error('Failed to switch network:', error);

    }

    }

    }

    Ajouter un réseau personnalisé

    async function addPolygonNetwork() {
    

    try {

    await window.ethereum.request({

    method: 'wallet_addEthereumChain',

    params: [{

    chainId: '0x89', // 137 en décimal

    chainName: 'Polygon Mainnet',

    nativeCurrency: {

    name: 'MATIC',

    symbol: 'MATIC',

    decimals: 18

    },

    rpcUrls: ['https://polygon-rpc.com'],

    blockExplorerUrls: ['https://polygonscan.com']

    }],

    });

    } catch (error) {

    console.error('Failed to add network:', error);

    }

    }

    Obtenir le réseau actuel

    async function getCurrentNetwork() {
    

    const chainId = await window.ethereum.request({ method: 'eth_chainId' });

    console.log('Current chain ID:', chainId); // ex. "0x1" pour Ethereum mainnet

    const networkMap = {

    '0x1': 'Ethereum Mainnet',

    '0xaa36a7': 'Sepolia Testnet',

    '0x89': 'Polygon Mainnet',

    '0xa4b1': 'Arbitrum One',

    };

    return networkMap[chainId] || 'Unknown Network';

    }

    Écouter les changements

    Changements de compte

    window.ethereum.on('accountsChanged', (accounts) => {
    

    if (accounts.length === 0) {

    // L'utilisateur a déconnecté tous les comptes

    console.log('Please connect to MetaMask');

    } else {

    // L'utilisateur a changé de compte

    console.log('Account changed to:', accounts[0]);

    setAccount(accounts[0]);

    }

    });

    Changements de réseau

    window.ethereum.on('chainChanged', (chainId) => {
    

    console.log('Network changed to:', chainId);

    // Recommandé : recharger la page pour éviter un état incohérent

    window.location.reload();

    });

    Connexion/Déconnexion

    window.ethereum.on('connect', (connectInfo) => {
    

    console.log('Connected to network:', connectInfo.chainId);

    });

    window.ethereum.on('disconnect', (error) => {

    console.log('Disconnected from network:', error);

    });

    Intégration avec Ethers.js

    L'API brute de MetaMask est verbeuse. Ethers.js fournit une abstraction plus propre.

    Installation

    npm install ethers

    Connecter le portefeuille avec Ethers.js

    import { BrowserProvider } from 'ethers';
    
    

    async function connectWallet() {

    if (typeof window.ethereum === 'undefined') {

    alert('Please install MetaMask');

    return;

    }

    // Demander l'accès au compte

    await window.ethereum.request({ method: 'eth_requestAccounts' });

    // Créer le provider ethers

    const provider = new BrowserProvider(window.ethereum);

    // Obtenir le signer (compte connecté)

    const signer = await provider.getSigner();

    const address = await signer.getAddress();

    console.log('Connected:', address);

    return { provider, signer, address };

    }

    Envoyer une transaction avec Ethers.js

    async function sendEther(to, amount) {
    

    const { signer } = await connectWallet();

    const tx = await signer.sendTransaction({

    to: to,

    value: ethers.parseEther(amount.toString()) // Convertir ETH en wei

    });

    console.log('Transaction sent:', tx.hash);

    // Attendre la confirmation

    const receipt = await tx.wait();

    console.log('Transaction confirmed:', receipt);

    return receipt;

    }

    // Usage

    await sendEther('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', 0.1);

    Interagir avec des smart contracts

    import { Contract } from 'ethers';
    
    

    async function interactWithContract() {

    const { signer } = await connectWallet();

    const contractAddress = '0x...';

    const abi = [

    "function transfer(address to, uint256 amount) returns (bool)",

    "function balanceOf(address owner) view returns (uint256)"

    ];

    const contract = new Contract(contractAddress, abi, signer);

    // Fonction de lecture (pas de coût de gas)

    const balance = await contract.balanceOf(await signer.getAddress());

    console.log('Balance:', ethers.formatEther(balance));

    // Fonction d'écriture (coûte du gas)

    const tx = await contract.transfer('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', ethers.parseEther('10'));

    await tx.wait();

    console.log('Transfer complete');

    }

    Lire les données de la blockchain

    async function getBlockchainData() {
    

    const provider = new BrowserProvider(window.ethereum);

    // Obtenir le numéro de bloc

    const blockNumber = await provider.getBlockNumber();

    console.log('Current block:', blockNumber);

    // Obtenir le prix du gas

    const feeData = await provider.getFeeData();

    console.log('Gas price:', ethers.formatUnits(feeData.gasPrice, 'gwei'), 'gwei');

    // Obtenir le solde

    const balance = await provider.getBalance('0x...');

    console.log('Balance:', ethers.formatEther(balance), 'ETH');

    }

    Signer des messages

    Personal Sign (messages lisibles)

    async function signMessage(message) {
    

    const accounts = await window.ethereum.request({ method: 'eth_accounts' });

    const signature = await window.ethereum.request({

    method: 'personal_sign',

    params: [message, accounts[0]],

    });

    console.log('Signature:', signature);

    return signature;

    }

    // Usage

    await signMessage('I agree to the terms of service');

    Avec Ethers.js

    async function signMessage(message) {
    

    const { signer } = await connectWallet();

    const signature = await signer.signMessage(message);

    return signature;

    }

    EIP-712 : Signature de données structurées typées

    Pour les données structurées (utilisé dans les fonctions permit, transactions sans gas) :

    async function signTypedData() {
    

    const { signer } = await connectWallet();

    const domain = {

    name: 'MyDApp',

    version: '1',

    chainId: 1,

    verifyingContract: '0x...'

    };

    const types = {

    Transfer: [

    { name: 'to', type: 'address' },

    { name: 'amount', type: 'uint256' }

    ]

    };

    const value = {

    to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',

    amount: ethers.parseEther('10')

    };

    const signature = await signer.signTypedData(domain, types, value);

    return signature;

    }

    Gestion des erreurs

    Codes d'erreur courants

    async function handleMetaMaskError() {
    

    try {

    await window.ethereum.request({ method: 'eth_requestAccounts' });

    } catch (error) {

    switch (error.code) {

    case 4001:

    // L'utilisateur a rejeté la demande

    console.log('Please connect to MetaMask');

    break;

    case -32002:

    // Demande déjà en attente

    console.log('Please open MetaMask to complete the request');

    break;

    case -32603:

    // Erreur interne

    console.error('Internal error:', error.message);

    break;

    default:

    console.error('Unknown error:', error);

    }

    }

    }

    Bonnes pratiques

    1. Toujours vérifier la présence de MetaMask

    if (typeof window.ethereum === 'undefined') {
    

    showInstallPrompt(); // Guider l'utilisateur pour installer MetaMask

    }

    2. Gérer les changements de compte

    window.ethereum.on('accountsChanged', (accounts) => {
    

    if (accounts.length === 0) {

    logout(); // L'utilisateur s'est déconnecté

    } else {

    updateAccount(accounts[0]);

    }

    });

    3. Recharger lors du changement de réseau

    window.ethereum.on('chainChanged', () => {
    

    window.location.reload(); // Empêche un état incohérent

    });

    4. Demander les permissions une fois

    N'appelez pas eth_requestAccounts à chaque chargement de page. Utilisez eth_accounts pour vérifier si déjà connecté.

    5. Fournir des messages d'erreur clairs

    if (error.code === 4001) {
    

    alert('You need to connect your wallet to use this feature');

    }

    6. Tester sur plusieurs réseaux

    Testez votre dApp sur mainnet, testnets (Sepolia) et L2s (Polygon, Arbitrum).

    7. Supporter le mobile

    MetaMask Mobile utilise WalletConnect pour le deep linking. Testez sur les navigateurs mobiles.

    Exemple complet React

    import { useState, useEffect } from 'react';
    

    import { BrowserProvider } from 'ethers';

    function App() {

    const [account, setAccount] = useState(null);

    const [provider, setProvider] = useState(null);

    useEffect(() => {

    if (window.ethereum) {

    // Vérifier si déjà connecté

    window.ethereum.request({ method: 'eth_accounts' })

    .then(accounts => {

    if (accounts.length > 0) {

    setAccount(accounts[0]);

    setProvider(new BrowserProvider(window.ethereum));

    }

    });

    // Écouter les changements de compte

    window.ethereum.on('accountsChanged', (accounts) => {

    setAccount(accounts[0] || null);

    });

    // Écouter les changements de réseau

    window.ethereum.on('chainChanged', () => {

    window.location.reload();

    });

    }

    }, []);

    const connectWallet = async () => {

    if (!window.ethereum) {

    alert('Please install MetaMask');

    return;

    }

    const accounts = await window.ethereum.request({

    method: 'eth_requestAccounts'

    });

    setAccount(accounts[0]);

    setProvider(new BrowserProvider(window.ethereum));

    };

    return (

    <div>

    {account ? (

    <div>

    <p>Connected: {account}</p>

    {/* Votre interface dApp */}

    </div>

    ) : (

    <button onClick={connectWallet}>Connect Wallet</button>

    )}

    </div>

    );

    }

    Conclusion

    L'intégration de MetaMask est essentielle pour toute dApp Ethereum. En suivant ce guide, vous pouvez détecter MetaMask, connecter des portefeuilles, envoyer des transactions et interagir avec des smart contracts de manière fluide. Combiné avec ethers.js, vous disposez d'une boîte à outils puissante pour construire des applications Web3 accessibles à des millions d'utilisateurs.

    Commencez à construire votre dApp aujourd'hui — intégrez MetaMask et donnez vie à vos smart contracts. Pratiquez l'intégration de portefeuilles avec les projets Web3 pratiques de Solingo pour maîtriser le développement blockchain full-stack.

    Prochaines étapes :

    • Construisez une dApp simple avec connexion de portefeuille
    • Implémentez le suivi de l'historique des transactions
    • Ajoutez le support de plusieurs portefeuilles (Coinbase Wallet, WalletConnect)
    • Apprenez les transactions sans gas avec les permits EIP-2612

    Prêt à mettre en pratique ?

    Applique ces concepts avec des exercices interactifs sur Solingo.

    Commencer gratuitement