Passer au contenu principal

Prérequis

Préparation du contrat

Le contrat d’exemple suivant sera utilisé tout au long de ce guide :
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

contract SimpleStorage {
    string private storedData;
    address public owner;
    
    event DataStored(string data, address indexed by);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
    constructor(string memory initialData) {
        storedData = initialData;
        owner = msg.sender;
        emit DataStored(initialData, msg.sender);
    }
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can perform this action");
        _;
    }
    
    function setData(string memory data) public onlyOwner {
        storedData = data;
        emit DataStored(data, msg.sender);
    }
    
    function getData() public view returns (string memory) {
        return storedData;
    }
    
    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0), "New owner cannot be zero address");
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }
}

Déployer avec Foundry

Foundry est une boîte à outils rapide basée sur Rust pour le développement Ethereum.
  1. Installez Foundry :
    curl -L https://foundry.paradigm.xyz | bash
    
    Il se peut que vous deviez sourcer votre fichier .bashrc ou .zshrc
  2. Configurez un nouveau projet Foundry :
    foundryup
    forge init my-plasma-project
    cd my-plasma-project
    
  3. Mettez à jour foundry.toml avec les paramètres du testnet Plasma :
    [profile.default]
    src = "src"
    out = "out"
    libs = ["lib"]
    solc_version = "0.8.28"
    optimizer = true
    optimizer_runs = 200
    
    [rpc_endpoints]
    plasma_testnet = "https://testnet-rpc.plasma.to"
    
  4. Créez un fichier .env à la racine de votre projet :
    PRIVATE_KEY=your_private_key_here
    RPC_URL=https://testnet-rpc.plasma.to
    
  5. Chargez les variables d’environnement :
    source .env
    
  6. Enregistrez le code du contrat sous src/SimpleStorage.sol, puis déployez :
    forge create src/SimpleStorage.sol:SimpleStorage \
        --rpc-url $RPC_URL \
        --private-key $PRIVATE_KEY \
        --constructor-args "Hello, Plasma!"
    
    Foundry affichera le hash de transaction de déploiement et l’adresse du contrat :
    [⠊] Compiling...
    [⠢] Compiling 1 files with Solc 0.8.28
    [⠆] Solc 0.8.28 finished in 124.81ms
    Compiler run successful!
    Warning: Dry run enabled, not broadcasting transaction
    
    Contract: SimpleStorage
    Transaction: {
      "from": "0xbd828f7679656f8f830b89611c933017442f2ebf",
      "to": null,
      "maxFeePerGas": "0xf",
      "maxPriorityFeePerGas": "0x1",
      "gas": "0x69f18",
    
    [...]
    
  7. Testez votre contrat déployé en utilisant l’outil cast de Foundry. Lisez d’abord les données stockées :
    cast call 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
        "getData()" \
        --rpc-url $RPC_URL
    
  8. Mettez ensuite à jour les données et relisez-les :
    # Update the stored data.
    cast send 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
        "setData(string)" "Updated from Foundry" \
        --private-key $PRIVATE_KEY \
        --rpc-url $RPC_URL
    
    # Read the stored data again.
    cast call 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
        "getData()" \
        --rpc-url $RPC_URL
    
    Cela devrait produire quelque chose comme :
    blockHash            0x68fbd2aaf1de9c577869056ca634f2103fa1695673a94d8c049d0b78d3733aac
    blockNumber          1200423
    contractAddress
    cumulativeGasUsed    21712
    effectiveGasPrice    8
    from                 0xBd828F7679656F8f830b89611C933017442F2EbF
    gasUsed              21712
    logs                 []
    logsBloom            0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    root
    status               1 (success)
    transactionHash      0xcf5b1fcc8d19f7cf7992f6e6a8b3ade74e07afbd0da0b9fce26bda4c9503a12b
    transactionIndex     0
    type                 2
    blobGasPrice
    blobGasUsed
    to                   0x742D35Cc6610c7532C8582D4C371aCb1D5F44D7F
    0x
    

Déployer avec Hardhat

Hardhat est un framework de développement complet avec une riche prise en charge des plugins.
  1. Assurez-vous d’avoir les éléments suivants :
  • Node.js 20+ (requis pour la compatibilité moderne avec Hardhat)
  • Familiarité avec le développement Ethereum
  • Un wallet avec des tokens de testnet (voir détails de la chaîne testnet)
Node.js 18 et versions inférieures ne sont plus prises en charge par Hardhat et peuvent provoquer des problèmes de compatibilité avec les modules ES.
  1. Vérifiez la version de Node.js :
    node --version
    
    Si vous utilisez Node.js 18 ou inférieur, mettez à niveau vers Node.js 20+ :
    # Using nvm (recommended)
    nvm install 20
    nvm use 20
    
    # Or using NodeSource repository (Ubuntu/Debian)
    curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
    sudo apt-get install -y nodejs
    
  2. Initialisez un nouveau projet Hardhat :
    mkdir my-plasma-hardhat-project
    cd my-plasma-hardhat-project
    npm init -y
    npm install --save-dev hardhat@latest @nomicfoundation/hardhat-toolbox@latest
    npm install dotenv@latest ethers@latest
    npx hardhat init
    
    Si vous rencontrez des problèmes de compatibilité, consultez la documentation Hardhat pour les dernières versions prises en charge.
    Choisissez Create a JavaScript project lorsque vous y êtes invité.
  3. Mettez à jour hardhat.config.js :
    require("@nomicfoundation/hardhat-toolbox");
    require("dotenv").config();
    
    /** @type import('hardhat/config').HardhatUserConfig */
    module.exports = {
      solidity: {
        version: "0.8.28",
        settings: {
          optimizer: {
            enabled: true,
            runs: 200
          }
        }
      },
      networks: {
        plasmaTestnet: {
          url: process.env.RPC_URL,
          chainId: 9746,
          accounts: [process.env.PRIVATE_KEY],
          gasPrice: 1000000000, // 1 gwei
        }
      },
      etherscan: {
        apiKey: {
          plasmaTestnet: process.env.ETHERSCAN_API_KEY
        },
        customChains: [
          {
            network: "plasmaTestnet",
            chainId: 9746,
            urls: {
              apiURL: "https://testnet.plasmascan.to/api",
              browserURL: "https://testnet.plasmascan.to/"
            }
          }
        ]
      }
    };
    
  4. Créez un fichier .env à la racine de votre projet :
    PRIVATE_KEY=your_private_key_here
    RPC_URL=https://testnet-rpc.plasma.to
    ETHERSCAN_API_KEY=your_api_key_for_verification
    
  5. Créez le répertoire scripts et le script de déploiement :
    mkdir scripts
    
  6. Créez scripts/deploy.js :
    const { ethers } = require("hardhat");
    
    async function main() {
      // Get the contract factory
      const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
    
      console.log("Deploying SimpleStorage contract...");
    
      // Deploy the contract with constructor arguments
      const simpleStorage = await SimpleStorage.deploy("Hello, Plasma from Hardhat!");
    
      // Wait for deployment to complete
      await simpleStorage.waitForDeployment();
    
      const contractAddress = await simpleStorage.getAddress();
      console.log("SimpleStorage deployed to:", contractAddress);
      console.log("Transaction hash:", simpleStorage.deploymentTransaction().hash);
    
      // Wait a few blocks for the transaction to be included
      console.log("Waiting for block confirmations...");
      await simpleStorage.deploymentTransaction().wait(5);
    
      console.log("✅ Deployment completed successfully!");
    }
    
    main()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error);
        process.exit(1);
      });
    
  7. Enregistrez le code du contrat sous contracts/SimpleStorage.sol, puis déployez :
    npx hardhat run scripts/deploy.js --network plasmaTestnet
    
  8. C’est terminé !

Déployer avec Ethers.js

Ethers.js fournit un flux de déploiement minimal et programmatique.
  1. Créez un nouveau projet :
    mkdir my-plasma-ethers-project
    cd my-plasma-ethers-project
    npm init -y
    npm install ethers dotenv solc
    
  2. Créez un fichier .env à la racine de votre projet :
    PRIVATE_KEY=<your_private_key_here>
    RPC_URL=https://testnet-rpc.plasma.to
    ETHERSCAN_API_KEY=your_api_key_for_verification
    
  3. Créez compile.js pour compiler votre contrat Solidity :
    const fs = require('fs');
    const solc = require('solc');
    require('dotenv').config();
    
    // Read the contract source code.
    const contractSource = fs.readFileSync('SimpleStorage.sol', 'utf8');
    
    // Prepare the input for the Solidity compiler.
    const input = {
      language: 'Solidity',
      sources: {
        'SimpleStorage.sol': {
          content: contractSource,
        },
      },
      settings: {
        outputSelection: {
          '*': {
            '*': ['*'],
          },
        },
        optimizer: {
          enabled: true,
          runs: 200,
        },
      },
    };
    
    // Compile the contract.
    const output = JSON.parse(solc.compile(JSON.stringify(input)));
    
    // Check for compilation errors.
    if (output.errors) {
      output.errors.forEach((error) => {
        console.error(error.formattedMessage);
      });
    }
    
    // Extract the contract data.
    const contract = output.contracts['SimpleStorage.sol']['SimpleStorage'];
    const abi = contract.abi;
    const bytecode = contract.evm.bytecode.object;
    
    // Save compilation artifacts.
    fs.writeFileSync('SimpleStorage.json', JSON.stringify({
      abi: abi,
      bytecode: bytecode
    }, null, 2));
    
    console.log('Contract compiled successfully!');
    
  4. Enregistrez votre contrat sous SimpleStorage.sol, puis compilez :
    node compile.js
    
    Cela devrait produire :
    Contract compiled successfully!
    
  5. Créez deploy.js :
    const { ethers } = require('ethers');
    const fs = require('fs');
    require('dotenv').config();
    
    async function deploy() {
      // Set up provider and wallet.
      const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
      const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
      
      console.log('Deploying from account:', wallet.address);
      
      // Check account balance.
      const balance = await provider.getBalance(wallet.address);
      console.log('Account balance:', ethers.formatEther(balance), 'XPL');
      
      // Load compiled contract.
      const contractData = JSON.parse(fs.readFileSync('SimpleStorage.json', 'utf8'));
      
      // Create contract factory.
      const factory = new ethers.ContractFactory(
        contractData.abi,
        contractData.bytecode,
        wallet
      );
      
      // Deploy the contract.
      console.log('Deploying contract...');
      const contract = await factory.deploy("Hello, Plasma from Ethers.js!", {
        gasLimit: 500000, // Set a reasonable gas limit.
        gasPrice: ethers.parseUnits('1', 'gwei'), // 1 gwei gas price.
      });
      
      // Wait for deployment.
      await contract.waitForDeployment();
      
      const contractAddress = await contract.getAddress();
      console.log('Contract deployed to:', contractAddress);
      console.log('Transaction hash:', contract.deploymentTransaction().hash);
      
      // Save deployment info.
      const deploymentInfo = {
        contractAddress: contractAddress,
        transactionHash: contract.deploymentTransaction().hash,
        deployer: wallet.address,
        network: 'plasmaTestnet',
        timestamp: new Date().toISOString()
      };
      
      fs.writeFileSync('deployment.json', JSON.stringify(deploymentInfo, null, 2));
      
      return contract;
    }
    
    async function interact(contract) {
      console.log('\nInteracting with deployed contract...');
      
      // Read initial data.
      const initialData = await contract.getData();
      console.log('Initial data:', initialData);
      
      // Update data.
      const updateTx = await contract.setData("Updated via Ethers.js");
      await updateTx.wait();
      console.log('Data updated. Transaction hash:', updateTx.hash);
      
      // Read updated data.
      const updatedData = await contract.getData();
      console.log('Updated data:', updatedData);
      
      // Get owner.
      const owner = await contract.owner();
      console.log('Contract owner:', owner);
    }
    
    // Main execution.
    deploy()
      .then(async (contract) => {
        await interact(contract);
        console.log('\nDeployment and interaction completed successfully!');
      })
      .catch((error) => {
        console.error('Error:', error);
        process.exit(1);
      });
    
  6. Exécutez le script de déploiement :
    node deploy.js
    
    Cela devrait produire quelque chose comme :
    Deploying from account: 0xBd828F7679656F8f830b89611C933017442F2EbF
    Account balance: 98539.897261933991888304 XPL
    Deploying contract...
    Contract deployed to: 0xf298A2A7BC526F9228B8C422D38f3c2E0D15449F
    Transaction hash: 0x3d16cc55b9148bac9ac20981d9748a0fc89861c6beb92a2f869bb09b75f685b2
    
    Interacting with deployed contract...
    Initial data: Hello, Plasma from Ethers.js!
    Data updated. Transaction hash: 0xe3328862ece5d0ca4ca84d25c4130d6749ec872c24bf76eea23dfa8c50c22505
    Updated data: Updated via Ethers.js
    Contract owner: 0xBd828F7679656F8f830b89611C933017442F2EbF
    
    Deployment and interaction completed successfully!
    

Vérifier le déploiement

Après déploiement avec l’une des méthodes ci-dessus, vérifiez le déploiement de votre contrat.

Dépannage

Problèmes de compatibilité des modules ES

Si vous rencontrez des erreurs telles que Error [ERR_REQUIRE_ESM]: require() of ES Module, cela signifie généralement :
  1. La version de Node.js est trop ancienne : Mettez à niveau vers Node.js 20+ comme mentionné dans les prérequis
  2. Décalage de versions de dépendances : Si la mise à niveau de Node.js n’est pas possible, vous pouvez rétrograder la dépendance problématique :
    npm install micro-eth-signer@0.10.0
    

Avertissements sur la version de Node.js

Si vous voyez des avertissements concernant des versions non prises en charge de Node.js :
WARNING: You are currently using Node.js v18.19.1, which is not supported by Hardhat
Mettez à niveau vers Node.js 20+ en suivant les étapes de la section des prérequis.

Fonds insuffisants

Error: insufficient funds for intrinsic transaction cost
Assurez-vous que votre wallet dispose de suffisamment de tokens de testnet. Visitez un faucet de testnet.

Mauvaise configuration de réseau

Error: network with chainId "1" doesn't match the configured chainId "9746"
Vérifiez que la configuration de votre réseau correspond aux détails de la chaîne testnet.

Échec d’estimation de gas

Error: cannot estimate gas
Définissez des limites de gas explicites dans votre configuration de déploiement :
// In your deploy script
const simpleStorage = await SimpleStorage.deploy("Hello, Plasma from Hardhat!", {
  gasLimit: 500000
});