> ## Documentation Index
> Fetch the complete documentation index at: https://docs.plasma.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Vérifier un contrat

> Ce guide explique comment vérifier des smart contracts sur Plasma en utilisant Foundry, Hardhat et Ethers.js. La vérification rend le code source du contrat accessible publiquement sur les explorateurs de blocs et garantit la transparence pour les utilisateurs.

## Prérequis

* Un contrat déployé sur le testnet Plasma. Voir [déployer un contrat](./deploy-a-contract.mdx) si vous n'en avez pas encore déployé un.
* Le code source de votre contrat et les paramètres de compilation.
* Les arguments du constructeur utilisés lors du déploiement (le cas échéant).

L'explorateur de blocs Plasma (`plasmascan.to`) propose une API de vérification compatible Etherscan. Les exemples ci-dessous utilisent cette API directement — aucun compte tiers n'est requis pour soumettre une vérification.

## Contrats d'exemple

Nous utiliserons deux contrats d'exemple pour démontrer à la fois des arguments de constructeur simples et complexes :

### Contrat simple

Un contrat basique de stockage de données qui illustre les concepts fondamentaux des smart contracts.

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

contract SimpleStorage {
    string private storedData;
    address public owner;
    
    constructor(string memory initialData) {
        storedData = initialData;
        owner = msg.sender;
    }
    
    function setData(string memory data) public {
        require(msg.sender == owner, "Only owner can set data");
        storedData = data;
    }
    
    function getData() public view returns (string memory) {
        return storedData;
    }
}
```

### Contrat complexe

Un système de coffre plus sophistiqué pour gérer les dépôts de tokens avec des paramètres configurables.

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

contract TokenVault {
    struct VaultConfig {
        uint256 minDeposit;
        uint256 maxDeposit;
        bool isActive;
    }
    
    address[] public authorisedTokens;
    VaultConfig public config;
    mapping(address => uint256) public balances;
    
    constructor(
        address[] memory _tokens,
        uint256 _minDeposit,
        uint256 _maxDeposit,
        bool _isActive
    ) {
        authorisedTokens = _tokens;
        config = VaultConfig(_minDeposit, _maxDeposit, _isActive);
    }
    
    function deposit(address token, uint256 amount) external {
        require(config.isActive, "Vault is not active");
        require(amount >= config.minDeposit, "Amount below minimum");
        require(amount <= config.maxDeposit, "Amount above maximum");
        balances[msg.sender] += amount;
    }
}
```

## Vérifier avec Foundry

[Foundry](https://getfoundry.sh) fournit la commande `forge verify-contract` pour la vérification de contrats.

1. Assurez-vous que votre `foundry.toml` inclut les paramètres de vérification :

   ```toml theme={null}
   [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"
   ```

2. Vérifiez le contrat. Pour le contrat SimpleStorage avec un argument de constructeur de type string :

   ```shell theme={null}
   forge verify-contract \
     --chain-id 9746 \
     --num-of-optimizations 200 \
     --watch \
     --constructor-args $(cast abi-encode "constructor(string)" "Hello, Plasma!") \
     --compiler-version v0.8.28+commit.7893614a \
     0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
     src/SimpleStorage.sol:SimpleStorage
   ```

   Pour le contrat TokenVault avec plusieurs arguments de constructeur :

   ```shell theme={null}
   # First, encode the constructor arguments.
   CONSTRUCTOR_ARGS=$(cast abi-encode \
       "constructor(address[],uint256,uint256,bool)" \
       "[0x1234567890123456789012345678901234567890,0x0987654321098765432109876543210987654321]" \
       1000000000000000000 \
       10000000000000000000 \
       true)

   forge verify-contract \
       --chain-id 9746 \
       --num-of-optimizations 200 \
       --watch \
       --constructor-args $CONSTRUCTOR_ARGS \
       --compiler-version v0.8.28+commit.7893614a \
       0x9876543210987654321098765432109876543210 \
       src/TokenVault.sol:TokenVault
   ```

3. Vérifiez le statut de la vérification. Foundry affichera l'état de vérification en temps réel avec le drapeau `--watch`. Recherchez :

   ```plaintext theme={null}
   Submitting verification for [src/SimpleStorage.sol:SimpleStorage] 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F.
   Submitted contract for verification:
           Response: `OK`
           GUID: `abc123def456ghi789`
           URL: https://testnet.plasmascan.to/address/0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F
   Contract verification status:
   Response: `NOTOK`
   Details: `Pending in queue`
   Contract verification status:
   Response: `OK`
   Details: `Pass - Verified`
   Contract successfully verified
   ```

## Vérifier avec Hardhat

[Hardhat](https://hardhat.org/) propose la vérification de contrats via le plugin `@nomicfoundation/hardhat-verify`.

1. Mettez à jour votre `hardhat.config.js` pour inclure les paramètres de vérification :

   ```javascript theme={null}
   require("@nomicfoundation/hardhat-toolbox");
   require("@nomicfoundation/hardhat-verify");
   require("dotenv").config();

   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]
       }
     },
     etherscan: {
       customChains: [
         {
           network: "plasmaTestnet",
           chainId: 9746,
           urls: {
             apiURL: "https://testnet.plasmascan.to/api",
             browserURL: "https://testnet.plasmascan.to/"
           }
         }
       ]
     },
     sourcify: {
       enabled: false
     }
   };
   ```

2. Vérifiez le contrat. Pour le contrat simple :

   ```shell theme={null}
   npx hardhat verify \
       --network plasmaTestnet \
       0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
       "Hello, Plasma!"
   ```

   Pour les contrats avec plusieurs arguments de constructeur, créez un script de vérification `scripts/verify.js` :

   ```javascript theme={null}
   const hre = require("hardhat");

   async function main() {
     const contractAddress = "0x9876543210987654321098765432109876543210";
     
     // Constructor arguments for TokenVault.
     const constructorArgs = [
       [
         "0x1234567890123456789012345678901234567890",
         "0x0987654321098765432109876543210987654321"
       ], // address[] _tokens
       "1000000000000000000", // uint256 _minDeposit (1e18, assuming 18 decimals)
       "10000000000000000000", // uint256 _maxDeposit (1e19, assuming 18 decimals)
       true // bool _isActive
     ];

     try {
       await hre.run("verify:verify", {
         address: contractAddress,
         constructorArguments: constructorArgs,
       });
       console.log("Contract verified successfully!");
     } catch (error) {
       console.error("Verification failed:", error);
     }
   }

   main()
     .then(() => process.exit(0))
     .catch((error) => {
       console.error(error);
       process.exit(1);
     });
   ```

3. Exécutez le script de vérification :

   ```shell theme={null}
   npx hardhat run scripts/verify.js --network plasmaTestnet
   ```

### Vérification automatisée pendant le déploiement

Vous pouvez aussi vérifier des contrats automatiquement pendant le déploiement en ajoutant la vérification à votre script de déploiement :

```javascript theme={null}
const { ethers } = require("hardhat");

async function main() {
  const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
  const simpleStorage = await SimpleStorage.deploy("Hello, Plasma!");
  
  await simpleStorage.waitForDeployment();
  const contractAddress = await simpleStorage.getAddress();
  
  console.log("SimpleStorage deployed to:", contractAddress);
  
  // Wait for a few block confirmations before verifying.
  console.log("Waiting for block confirmations...");
  await simpleStorage.deploymentTransaction().wait(5);
  
  // Verify the contract.
  try {
    await hre.run("verify:verify", {
      address: contractAddress,
      constructorArguments: ["Hello, Plasma!"],
    });
    console.log("Contract verified successfully!");
  } catch (error) {
    console.log("Verification failed:", error.message);
  }
}

main();
```

## Vérifier avec Ethers.js

[Ethers.js](https://ethers.org/) nécessite des appels API manuels à l'explorateur de blocs pour la vérification. Cette approche vous donne un contrôle total sur le processus de vérification.

1. Installez les dépendances requises :

   ```shell theme={null}
   npm install ethers dotenv axios form-data
   ```

2. Créez le script de vérification `verify-ethers.js` :

   ```javascript theme={null}
   const axios = require('axios');
   const fs = require('fs');
   require('dotenv').config();

   async function verifyContract(contractAddress, sourceCode, contractName, constructorArgs = "") {
     const apiUrl = "https://testnet.plasmascan.to/api";
     
     const data = {
       module: 'contract',
       action: 'verifysourcecode',
       contractaddress: contractAddress,
       sourceCode: sourceCode,
       codeformat: 'solidity-single-file',
       contractname: contractName,
       compilerversion: 'v0.8.28+commit.7893614a',
       optimizationUsed: '1',
       runs: '200',
       constructorArguements: constructorArgs, // Note: API uses this spelling.
       evmversion: 'default',
       licenseType: '3' // MIT License
     };

     try {
       console.log('Submitting contract for verification...');
       const response = await axios.post(apiUrl, new URLSearchParams(data));
       
       if (response.data.status === '1') {
         const guid = response.data.result;
         console.log('Verification submitted successfully!');
         console.log('GUID:', guid);
         
         // Check verification status.
         await checkVerificationStatus(guid);
       } else {
         console.error('Verification submission failed:', response.data.result);
       }
     } catch (error) {
       console.error('Error submitting verification:', error.message);
     }
   }

   async function checkVerificationStatus(guid) {
     const apiUrl = "https://testnet.plasmascan.to/api";
     const maxAttempts = 30;
     let attempts = 0;

     while (attempts < maxAttempts) {
       try {
         const response = await axios.get(apiUrl, {
           params: {
             module: 'contract',
             action: 'checkverifystatus',
             guid: guid
           }
         });

         const status = response.data.status;
         const result = response.data.result;

         if (status === '1') {
           console.log('✅ Contract verified successfully!');
           console.log('Result:', result);
           break;
         } else if (result.includes('Fail')) {
           console.error('❌ Verification failed:', result);
           break;
         } else {
           console.log('⏳ Verification pending...');
           attempts++;
           
           if (attempts < maxAttempts) {
             await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds.
           }
         }
       } catch (error) {
         console.error('Error checking status:', error.message);
         break;
       }
     }

     if (attempts >= maxAttempts) {
       console.log('⚠️ Verification status check timed out. Please check manually.');
     }
   }

   // Verify SimpleStorage contract.
   async function verifySimpleStorage() {
     const contractAddress = "0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F";
     const sourceCode = fs.readFileSync('SimpleStorage.sol', 'utf8');
     const constructorArgs = "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20506c61736d612100000000000000000000000000000000000000";
     
     await verifyContract(contractAddress, sourceCode, "SimpleStorage", constructorArgs);
   }

   // Verify TokenVault contract.
   async function verifyTokenVault() {
     const contractAddress = "0x9876543210987654321098765432109876543210";
     const sourceCode = fs.readFileSync('TokenVault.sol', 'utf8');
     
     // Complex constructor arguments (ABI encoded).
     const constructorArgs = "0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000123456789012345678901234567890123456789000000000000000000000000098765432109876543210987654321098765432100";
     
     await verifyContract(contractAddress, sourceCode, "TokenVault", constructorArgs);
   }

   // Run verification (uncomment the one you need).
   verifySimpleStorage();
   // verifyTokenVault();
   ```

3. Encodez les arguments du constructeur. Pour des arguments de constructeur complexes, vous devez les encoder en ABI. Vous pouvez utiliser l'outil `cast` de Foundry :

   ```shell theme={null}
   # For SimpleStorage with string argument.
   cast abi-encode "constructor(string)" "Hello, Plasma!"

   # For TokenVault with complex arguments.
   cast abi-encode \
       "constructor(address[],uint256,uint256,bool)" \
       "[0x1234567890123456789012345678901234567890,0x0987654321098765432109876543210987654321]" \
       1000000000000000000 \
       10000000000000000000 \
       true
   ```

4. Enfin, lancez la vérification :

   ```shell theme={null}
   node verify-ethers.js
   ```

## Vérifier le statut de vérification

Après la vérification, vous pouvez vérifier si elle a réussi :

### Sur l'explorateur de blocs

1. Visitez l'[explorateur du testnet Plasma](https://testnet.plasmascan.to/).
2. Recherchez l'adresse de votre contrat.
3. Recherchez une coche verte à côté de l'onglet « Contract ».
4. Cliquez sur l'onglet « Contract » pour voir le code source vérifié.

### Par programmation

1. Créez un script de vérification de statut `check-verification.js` :

   ```javascript theme={null}
   const axios = require('axios');
   require('dotenv').config();

   async function checkIfVerified(contractAddress) {
     const apiUrl = "https://testnet.plasmascan.to/api";
     
     try {
       const response = await axios.get(apiUrl, {
         params: {
           module: 'contract',
           action: 'getsourcecode',
           address: contractAddress,
         }
       });

       const result = response.data.result[0];
       
       if (result.SourceCode && result.SourceCode !== '') {
         console.log('✅ Contract is verified!');
         console.log('Contract Name:', result.ContractName);
         console.log('Compiler Version:', result.CompilerVersion);
         console.log('Optimisation Used:', result.OptimizationUsed);
         return true;
       } else {
         console.log('❌ Contract is not verified');
         return false;
       }
     } catch (error) {
       console.error('Error checking verification status:', error.message);
       return false;
     }
   }

   // Check your contract.
   checkIfVerified("0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F");
   ```

## Méthodes alternatives

Bien que les explorateurs de blocs soient la méthode de vérification la plus courante, vous pouvez également utiliser :

### Sourcify

[Sourcify](https://sourcify.dev/) propose une vérification décentralisée des contrats :

```shell theme={null}
# Install Sourcify CLI.
npm install -g @ethereum-sourcify/cli

# Verify contract.
sourcify verify \
    --network 9746 \
    --address 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
    --files contracts/SimpleStorage.sol
```

### Tenderly

[Tenderly](https://tenderly.co/) propose la vérification dans le cadre de sa plateforme de débogage. Consultez leur [documentation](https://docs.tenderly.co/contract-verification) pour plus de détails.

## Aplatissement de contrat

Pour les contrats avec des imports ou des bibliothèques, vous devrez peut-être aplatir votre contrat en un seul fichier avant la vérification. Les outils populaires incluent :

* [forge flatten de Foundry](https://book.getfoundry.sh/reference/forge/forge-flatten)
* [plugin flatten de Hardhat](https://github.com/NomicFoundation/hardhat/tree/main/packages/hardhat-core#flattening-contracts)
* [Truffle Flattener](https://github.com/nomiclabs/truffle-flattener)

Pour les projets complexes avec des bibliothèques externes, consultez la [documentation de vérification Hardhat](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify) pour les options de configuration avancées.

## Dépannage

### Décalage d'arguments de constructeur

```plaintext theme={null}
Error: Invalid constructor arguments provided
```

Vérifiez à deux reprises que vos arguments de constructeur correspondent exactement à ceux utilisés lors du déploiement. Utilisez `cast abi-encode` pour vérifier l'encodage.

### Décalage de version de compilateur

```plaintext theme={null}
Error: Compilation failed
```

Assurez-vous que la version du compilateur dans votre requête de vérification correspond à la version utilisée lors de la compilation.

### Décalage de paramètres d'optimisation

```plaintext theme={null}
Error: Bytecode doesn't match
```

Vérifiez que les paramètres d'optimisation (activé/désactivé et nombre d'exécutions) correspondent à vos paramètres de compilation.

### Déjà vérifié

```plaintext theme={null}
Error: Contract source code already verified
```

Cela signifie que la vérification a déjà réussi. Vérifiez sur l'explorateur de blocs pour confirmer.

### Limitation de débit

```plaintext theme={null}
Error: Rate limit exceeded
```

Attendez quelques minutes avant de réessayer. Envisagez de mettre à niveau votre plan API si vous avez besoin de limites plus élevées.
