Zum Hauptinhalt springen

Voraussetzungen

  • Ein auf das Plasma Testnet deployter Vertrag. Siehe Vertrag deployen, falls Sie noch keinen deployt haben.
  • Quellcode Ihres Vertrags und Kompilierungseinstellungen.
  • Konstruktor-Argumente, die beim Deployment verwendet wurden (falls vorhanden).
Der Plasma-Block-Explorer (plasmascan.to) stellt eine Etherscan-kompatible Verifizierungs-API bereit. Die folgenden Beispiele nutzen diese API direkt — es ist kein Drittanbieterkonto zum Einreichen einer Verifizierung erforderlich.

Beispielverträge

Wir verwenden zwei Beispielverträge, um sowohl einfache als auch komplexe Konstruktor-Argumente zu demonstrieren:

Einfacher Vertrag

Ein einfacher Datenspeicher-Vertrag, der grundlegende Smart-Contract-Konzepte demonstriert.
// 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;
    }
}

Komplexer Vertrag

Ein anspruchsvolleres Vault-System zur Verwaltung von Token-Einzahlungen mit konfigurierbaren Parametern.
// 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;
    }
}

Mit Foundry verifizieren

Foundry bietet den forge verify-contract-Befehl zur Vertragsverifizierung.
  1. Stellen Sie sicher, dass Ihre foundry.toml die Verifizierungseinstellungen enthält:
    [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. Den Vertrag verifizieren. Für den SimpleStorage-Vertrag mit einem String-Konstruktor-Argument:
    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
    
    Für den TokenVault-Vertrag mit mehreren Konstruktor-Argumenten:
    # 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. Verifizierungsstatus prüfen. Foundry zeigt mit dem --watch-Flag den Verifizierungsstatus in Echtzeit an. Achten Sie auf:
    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
    

Mit Hardhat verifizieren

Hardhat bietet Vertragsverifizierung über das @nomicfoundation/hardhat-verify-Plugin.
  1. Aktualisieren Sie Ihre hardhat.config.js, um Verifizierungseinstellungen aufzunehmen:
    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. Den Vertrag verifizieren. Für den einfachen Vertrag:
    npx hardhat verify \
        --network plasmaTestnet \
        0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
        "Hello, Plasma!"
    
    Für Verträge mit mehreren Konstruktor-Argumenten erstellen Sie ein Verifizierungsskript scripts/verify.js:
    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. Das Verifizierungsskript ausführen:
    npx hardhat run scripts/verify.js --network plasmaTestnet
    

Automatisierte Verifizierung während des Deployments

Sie können Verträge auch automatisch während des Deployments verifizieren, indem Sie die Verifizierung in Ihr Deployment-Skript einfügen:
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();

Mit Ethers.js verifizieren

Ethers.js erfordert manuelle API-Aufrufe an den Block-Explorer für die Verifizierung. Dieser Ansatz gibt Ihnen volle Kontrolle über den Verifizierungsprozess.
  1. Erforderliche Abhängigkeiten installieren:
    npm install ethers dotenv axios form-data
    
  2. Verifizierungsskript verify-ethers.js erstellen:
    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. Konstruktor-Argumente kodieren. Für komplexe Konstruktor-Argumente müssen Sie diese ABI-kodieren. Sie können Foundrys cast-Tool verwenden:
    # 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. Abschließend die Verifizierung ausführen:
    node verify-ethers.js
    

Verifizierungsstatus prüfen

Nach der Verifizierung können Sie prüfen, ob sie erfolgreich war:

Auf dem Block-Explorer

  1. Besuchen Sie den Plasma Testnet Explorer.
  2. Suchen Sie nach Ihrer Vertragsadresse.
  3. Achten Sie auf ein grünes Häkchen neben dem Tab „Contract”.
  4. Klicken Sie auf den Tab „Contract”, um den verifizierten Quellcode anzuzeigen.

Programmatisch

  1. Ein Statusprüfungsskript check-verification.js erstellen:
    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");
    

Alternative Methoden

Block-Explorer sind zwar die häufigste Verifizierungsmethode, aber Sie können auch verwenden:

Sourcify

Sourcify bietet dezentrale Vertragsverifizierung:
# Install Sourcify CLI.
npm install -g @ethereum-sourcify/cli

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

Tenderly

Tenderly bietet Verifizierung als Teil seiner Debugging-Plattform. Details siehe deren Dokumentation.

Vertrag flatten

Für Verträge mit Imports oder Bibliotheken müssen Sie Ihren Vertrag möglicherweise vor der Verifizierung in eine einzelne Datei „flatten”. Beliebte Tools sind: Für komplexe Projekte mit externen Bibliotheken sehen Sie die Hardhat-Verifizierungsdokumentation für erweiterte Konfigurationsoptionen.

Fehlerbehebung

Konstruktor-Argument-Abweichung

Error: Invalid constructor arguments provided
Überprüfen Sie nochmals, ob Ihre Konstruktor-Argumente exakt mit denen während des Deployments übereinstimmen. Verwenden Sie cast abi-encode, um die Kodierung zu prüfen.

Compiler-Versionsabweichung

Error: Compilation failed
Stellen Sie sicher, dass die Compiler-Version in Ihrer Verifizierungsanfrage mit der bei der Kompilierung verwendeten Version übereinstimmt.

Abweichung der Optimierungs-Einstellungen

Error: Bytecode doesn't match
Stellen Sie sicher, dass die Optimierungs-Einstellungen (aktiviert/deaktiviert und Anzahl der Runs) mit Ihren Kompilierungseinstellungen übereinstimmen.

Bereits verifiziert

Error: Contract source code already verified
Das bedeutet, dass die Verifizierung zuvor erfolgreich war. Prüfen Sie zur Bestätigung den Block-Explorer.

Rate-Limiting

Error: Rate limit exceeded
Warten Sie einige Minuten, bevor Sie es erneut versuchen. Erwägen Sie ein Upgrade Ihres API-Plans, wenn Sie höhere Limits benötigen.