मुख्य सामग्री पर जाएं
इन पर काम करता है: Virtual Environments और सार्वजनिक नेटवर्क (mainnets और testnets)। समान plugin दोनों को संभालता है; hardhat.config.ts में इसे सही नेटवर्क पर इंगित करें।
यह गाइड आपको @tenderly/hardhat-tenderly का उपयोग करके proxy contract सत्यापन के बारे में बताएगा।

आवश्यकताएँ

स्वचालित proxy सत्यापन @tenderly/hardhat-tenderly पर बिना किसी अतिरिक्त सेटअप के काम करता है:
  • >= 1.10.0 (Ethers 5 line)
  • >= 2.1.0 (Ethers 6 line)
npm update @tenderly/hardhat-tenderly
यह केवल तभी काम करता है जब आप @openzeppelin/hardhat-upgrades के साथ proxies को deploy करते हैं। Hardhat Ignition अभी proxy सत्यापन के लिए समर्थित नहीं है यदि आप plugin के निचले संस्करण पर हैं और upgrade नहीं कर सकते, तो नीचे दिए गए manual workaround का उपयोग करें।

स्वचालित सत्यापन

यह plugin तीन proxy patterns को सत्यापित करता है: TransparentUpgradeableProxy, UUPSUpgradeableProxy, और BeaconProxy
1
auto-populate flag सेट करें
2
अंदर से, plugin @openzeppelin/hardhat-upgrades extension के साथ @nomicfoundation/hardhat-verify को drive करता है। TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG=true सेट करने से plugin आपके लिए @nomicfoundation/hardhat-verify का verification URL populate कर देता है।
3
TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG=true
4
deployment script लिखें
5
अधिक स्पष्ट दृश्य के लिए, आप इस GitHub repo को देख सकते हैं और पूरा उदाहरण देखने के लिए scripts/proxy/ पर जा सकते हैं।
6
Automatic
@openzeppelin/hardhat-upgrades extension से deployProxy का उपयोग करके proxy को हमेशा की तरह deploy करें।
आगे इसके साथ interact करने के लिए आपको waitForDeployment function द्वारा लौटाए गए object को capture करना चाहिए।
अंदर से, स्वचालित सत्यापन deployProxy को wrap करके, और deployment के पूरा होने की प्रतीक्षा करके implement किया जाता है।

async function main() {
    console.log(
        "🖖🏽[ethers] Deploying TransparentUpgradeableProxy with VotingLogic as implementation on Tenderly.",
    );

    const VotingLogic = await ethers.getContractFactory("VotingLogic");
    let proxyContract = await upgrades.deployProxy(VotingLogic);
    proxyContract = await proxyContract.waitForDeployment();

    const proxyAddress = await proxyContract.getAddress();

    console.log("VotingLogic proxy deployed to:", proxyAddress);
    console.log(
        "VotingLogic impl deployed to:",
        await getImplementationAddress(ethers.provider, proxyAddress),
    );
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});
Manual
manual verification method के साथ proxy का सत्यापन तब किया जाता है जब proxy contract deploy हो चुका होता है, tenderly.verify() function को कॉल करके।

async function main() {
    console.log(
        "🖖🏽[ethers] Deploying TransparentUpgradeableProxy with VotingLogic as implementation on Tenderly.",
    );

    const VotingLogic = await ethers.getContractFactory("VotingLogic");
    let proxyContract = await upgrades.deployProxy(VotingLogic);
    proxyContract = await proxyContract.waitForDeployment();

    const proxyAddress = await proxyContract.getAddress();

    console.log("VotingLogic proxy deployed to:", proxyAddress);
    console.log(
        "VotingLogic impl deployed to:",
        await getImplementationAddress(ethers.provider, proxyAddress),
    );

    await tenderly.verify({
        name: ProxyPlaceholderName,
        address: proxyAddress,
    });
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});
7
script चलाएँ
8
Virtual Environment
TENDERLY_AUTOMATIC_VERIFICATION=true \
TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG=true \
npx hardhat run scripts/deploy.ts
Public network
किसी सार्वजनिक mainnet या testnet पर deploy करते समय, यह निर्दिष्ट करें कि आप सार्वजनिक या निजी सत्यापन चाहते हैं।
TENDERLY_AUTOMATIC_VERIFICATION=true \
TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG=true \
TENDERLY_PRIVATE_VERIFICATION=true \
npx hardhat run scripts/deploy.ts --network mainnet_base

निचले संस्करणों के लिए Workaround

@tenderly/hardhat-tenderly के संस्करण < 1.10.0 और < 2.1.0 का उपयोग करते समय, यह workaround स्वचालित सत्यापन को सक्षम करेगा। आपको निम्नलिखित को सत्यापित करने की आवश्यकता है:
  • Proxy contract (जैसे OpenZeppelin’s proxies)
  • Proxy के पीछे Implementation
  • Implementation की किसी भी dependencies
  • Upgrades के साथ deploy किए गए नए implementation instances
सत्यापन प्रक्रिया proxy contract type और implementation के आधार पर भिन्न होती है।

अवलोकन

इस गाइड में, हम OpenZeppelin के UUPSUpgradeable, TransparentUpgradeableProxy, और BeaconProxy विकल्पों के सत्यापन को प्रदर्शित करने के लिए एक उदाहरण Hardhat project और @tenderly/hardhat-tenderly plugin का उपयोग करेंगे।
Proxy contracts को manually सत्यापित करने की आवश्यकता है। स्वचालित सत्यापन को इस प्रकार बंद करें:
example.ts
// use manual verification
tenderly.setup({ automaticVerifications: false });
Deploy किए गए implementation का address प्राप्त करने के लिए, @openzeppelin/upgrades-core package और getImplementationAddress function का उपयोग करें। Proxy implementation को सत्यापित करना आमतौर पर सीधा है; इसे किसी भी अन्य contract की तरह सत्यापित करें।
example.ts
await tenderly.verify({
  // the new implementation contract
  name: 'VaultV2',
  // the address where implementation is deployed
  address: await getImplementationAddress(ethers.provider, await proxy.getAddress()),
});
Proxy instance को सत्यापित करने के लिए, आपको ये दो प्रारंभिक चरण पूरे करने होंगे:
  1. उपयोग किए जा रहे proxy के type के आधार पर proxy के सटीक smart contract को load करें, ताकि इसे compile किया जा सके। आपको एक dummy .sol फ़ाइल बनाकर compiler के माध्यम से proxy contracts को import करना होगा।
  2. उन settings को निर्दिष्ट करने के लिए hardhat.config.ts को Modify करें जिनके साथ OpenZeppelin contracts compile किए गए थे।
एक बार ये चरण पूरे हो जाने के बाद, आप proxy को किसी भी अन्य contract की तरह सत्यापित करने के लिए आगे बढ़ सकते हैं।
example.ts
await tenderly.verify({
  name: 'ERC1967Proxy', // or TransparentUpgradeableProxy or BeaconProxy
  address: await proxy.getAddress(),
});
1
example repo को Clone करें
2
git clone git@github.com:Tenderly/tenderly-examples.git
cd contract-verifications
npm i
3
Tenderly CLI सेट अप करें
4
brew tap tenderly/tenderly && brew install tenderly
tenderly login
5
Non-Homebrew install विकल्पों के लिए Tenderly CLI repo देखें।
6
Hardhat को configure करें
7
hardhat.config.ts में, tenderly.username और tenderly.project को अपने project और username slugs पर सेट करें।
8
एक Virtual Environment बनाएँ
9
Contracts को deploy और सत्यापित करने का सबसे तेज़ तरीका Virtual Environment पर है।
10
Tenderly Dashboard में, Virtual Environments खोलें और एक नया बनाएँ। fork करने के लिए base network और एक Chain ID चुनें, फिर Virtual Environment के विवरण पृष्ठ से Admin RPC URL copy करें।
11
अपनी .env फ़ाइल में RPC URL जोड़ें:
12
TENDERLY_VIRTUAL_TESTNET_RPC=https://virtual.<network>.rpc.tenderly.co/<your-uuid>
13
फिर इसे hardhat.config.ts में reference करें:
14
networks: {
  virtualMainnet: {
    url: process.env.TENDERLY_VIRTUAL_TESTNET_RPC!,
    chainId: 73571, // the Chain ID you set when creating the Virtual Environment
  },
},
15
पूर्ण walkthrough के लिए Virtual Environment quickstart देखें।
16
tests चलाएँ
17
rm -rf .openzeppelin && npx hardhat test --network virtualMainnet
18
Contracts को redeploy करते समय, पहले .openzeppelin folder को हटा दें। यह proxies और उनके implementations के बारे में जानकारी cache करता है।
19
proxy contracts को load करें
20
Proxy contract को सत्यापित करने के लिए, एक DummyProxy.sol फ़ाइल बनाएँ और उन OpenZeppelin proxy contracts को import करें जिनके साथ आप काम कर रहे हैं। ऐसा करने से, ये contracts load हो जाते हैं और compiler से गुज़र जाते हैं, जिससे आप सत्यापन के दौरान proxy के सटीक contract source को reference कर सकते हैं।
21
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;


abstract contract ERC1967ProxyAccess is ERC1967Proxy {}
abstract contract UpgradableBeaconAccess is UpgradeableBeacon {}
abstract contract BeaconProxyAccess is BeaconProxy {}
abstract contract TransparentUpgradeableProxyAccess is TransparentUpgradeableProxy {}
22
Solidity compiler overrides को configure करें
23
निम्नलिखित overrides map @openzeppelin/contracts-upgradeable संस्करण 4.9.1 के लिए निकाला गया था। यह package के अन्य संस्करणों के लिए भिन्न हो सकता है।
24
OpenZeppelin के proxy contracts को compile करने के बाद, आपको निम्नलिखित को भी निर्दिष्ट करना होगा:
25
  • Solidity compiler का संस्करण जो contracts को compile करने के लिए उपयोग किया गया था
  • Openzeppelin के upgrades plugin द्वारा proxy deployment/upgrades करते समय उपयोग की गई Optimization settings
  • 26
    hardhat-tenderly plugin सत्यापन के लिए smart contracts के सोर्स कोड और compiler settings दोनों का उपयोग करता है। यदि इनमें से कोई भी setting गलत है, तो सत्यापन विफल हो जाएगा।
    27
    अपने Hardhat User config object के config.solidity अनुभाग में निम्नलिखित overrides map जोड़ें।
    28
    const config: HardhatUserConfig = {
      solidity: {
        compilers: [{ version: '0.8.18' } /* OTHER COMPILER VERSIONS*/],
        overrides: {
          '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol': {
            version: '0.8.9',
            settings: {
              optimizer: {
                enabled: true,
                runs: 200,
              },
            },
          },
          '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol': {
            version: '0.8.9',
            settings: {
              optimizer: {
                enabled: true,
                runs: 200,
              },
            },
          },
    
          '@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol': {
            version: '0.8.9',
            settings: {
              optimizer: {
                enabled: true,
                runs: 200,
              },
            },
          },
          '@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol': {
            version: '0.8.9',
            settings: {
              optimizer: {
                enabled: true,
                runs: 200,
              },
            },
          },
          'contracts/proxy.sol': {
            version: '0.8.9',
            settings: {
              optimizer: {
                enabled: true,
                runs: 200,
              },
            },
          },
        },
      },
      /* OTHER CONFIG */
    };
    

    Proxy type के अनुसार सत्यापित करें

    ये code samples दिखाते हैं कि OpenZeppelin के तीन proxy patterns के लिए implementation और proxy को कैसे सत्यापित किया जाए। ये उदाहरण एक proxied Vault contract का उपयोग करते हैं जो एक ERC-20 token (TToken) को reference करता है।

    UUPS proxy

    UUPS proxy और underlying जानकारी को सत्यापित करने के लिए, hardhat-tenderly plugin को दो बार कॉल करें:
    1. Implementation को सत्यापित करने के लिए, आपको निम्नलिखित प्रदान करने की आवश्यकता है:
    • अपने proxied contract का name (हमारे मामले में Vault)
    • वह address जहाँ contract deploy किया गया था, @openzeppelin/upgrades-core से getImplementationAddress method का उपयोग करके।
    1. Proxy को सत्यापित करने के लिए, निम्नलिखित प्रदान करें:
    • proxy contract name के रूप में ERC1967Proxy
    • Proxy का address proxy.address
    example.ts
    await tenderly.verify(
      {
        name: 'Vault',
        address: await getImplementationAddress(ethers.provider, await proxy.getAddress()),
      },
      {
        name: 'ERC1967Proxy',
        address: await proxy.getAddress(),
      },
    );
    

    पूर्ण Code नमूना

    यहाँ एक पूर्ण Hardhat test है जो निम्न कार्य करता है:
    • TToken को Deploy करता है (vault के लिए आवश्यक)
    • Vault को एक proxy के रूप में Deploy करता है, TToken contract के साथ initialize करता है
    • await proxy.getAddress() पर deploy किए गए proxy (ERC1967Proxy) instance को सत्यापित करता है
    • getImplementationAddress(ethers.provider, await proxy.getAddress()) पर deploy किए गए implementation instance Vault को सत्यापित करता है
    • Proxy को VaultV2 पर Upgrade करता है
    example.ts
    
    describe('Vault', () => {
      it('uups proxy deployment and verification', async () => {
        const VaultFactory = await ethers.getContractFactory('Vault');
        const TokenFactory = await ethers.getContractFactory('TToken');
    
        let token = await ethers.deployContract('TToken');
        token = await token.waitForDeployment();
        const tokenAddress = await token.getAddress();
    
        await tenderly.verify({
          name: 'TToken',
          address: tokenAddress,
        });
    
        let proxy = await upgrades.deployProxy(VaultFactory, [tokenAddress], {
          kind: 'uups',
        });
        await proxy.waitForDeployment();
        const proxyAddress = await proxy.getAddress();
    
        console.log('Deployed UUPS ', {
          proxy: proxyAddress,
          implementation: await getImplementationAddress(ethers.provider, proxyAddress),
        });
    
        await tenderly.verify(
          {
            name: 'Vault',
            address: await getImplementationAddress(ethers.provider, proxyAddress),
          },
          {
            name: 'ERC1967Proxy',
            address: proxyAddress,
          },
        );
    
        // upgrade
        const vaultV2Factory = await ethers.getContractFactory('VaultV2');
        proxy = (await upgrades.upgradeProxy(proxy, vaultV2Factory, {
          kind: 'uups',
        })) as Vault;
    
        await proxy.waitForDeployment();
    
        console.log('Upgraded UUPS ', {
          proxy: proxyAddress,
          implementation: await getImplementationAddress(ethers.provider, proxyAddress),
        });
    
        await tenderly.verify({
          name: 'VaultV2',
          address: await getImplementationAddress(ethers.provider, proxyAddress),
        });
      });
    });
    

    Transparent proxy

    UUPS proxy और underlying जानकारी को सत्यापित करने के लिए, दो contracts पास करते हुए hardhat-tenderly को कॉल करें: implementation के लिए Vault, और proxy के लिए स्वयं TransparentUpgradeableProxy
    example.ts
    await tenderly.verify(
      {
        name: 'Vault',
        address: await getImplementationAddress(ethers.provider, await proxy.getAddress()),
      },
      {
        name: 'TransparentUpgradeableProxy',
        address: await proxy.getAddress(),
      },
    );
    
    1. Implementation को सत्यापित करने के लिए, निम्नलिखित प्रदान करें:
    • अपने proxied contract का name (हमारे मामले में Vault)
    • वह address जहाँ contract deploy किया गया था, @openzeppelin/upgrades-core से getImplementationAddress method का उपयोग करके।
    1. Proxy को सत्यापित करने के लिए, निम्नलिखित प्रदान करें:
    • proxy contract name के रूप में TransparentUpgradeableProxy
    • Proxy का address await proxy.getAddress()

    पूर्ण Code नमूना

    example.ts
    
    describe('Vault', () => {
      it('transparent upgradable proxy deployment and verification', async () => {
        const VaultFactory = await ethers.getContractFactory('Vault');
        const TokenFactory = await ethers.getContractFactory('TToken');
    
        let token = await ethers.deployContract('TToken');
        token = await token.waitForDeployment();
        const tokenAddress = await token.getAddress();
    
        await tenderly.verify({
          name: 'TToken',
          address: tokenAddress,
        });
    
        let proxy = await upgrades.deployProxy(VaultFactory, [tokenAddress], {
          kind: 'transparent',
        });
        await proxy.waitForDeployment();
        const proxyAddress = await proxy.getAddress();
    
        console.log('Deployed transparent', {
          proxy: proxyAddress,
          implementation: await getImplementationAddress(ethers.provider, proxyAddress),
        });
    
        await tenderly.verify(
          {
            name: 'Vault',
            address: await getImplementationAddress(ethers.provider, proxyAddress),
          },
          {
            name: 'TransparentUpgradeableProxy',
            address: proxyAddress,
          },
        );
    
        // upgrade
        const vaultV2Factory = await ethers.getContractFactory('VaultV2');
    
        proxy = (await upgrades.upgradeProxy(proxy, vaultV2Factory, {
          kind: 'transparent',
        })) as Vault;
    
        await proxy.waitForDeployment();
    
        console.log('Upgraded transparent ', {
          proxy: proxyAddress,
          implementation: await getImplementationAddress(ethers.provider, proxyAddress),
        });
    
        await tenderly.verify({
          name: 'VaultV2',
          address: await getImplementationAddress(ethers.provider, proxyAddress),
        });
      });
    });
    

    Beacon proxy

    Beacon proxy और underlying जानकारी को सत्यापित करने के लिए, आपको दो contracts सत्यापित करने होंगे: Vault (implementation) और OpenZeppelin का UpgradableBeacon:
    example.ts
    await tenderly.verify(
      {
        name: 'Vault',
        address: await getImplementationAddressFromBeacon(ethers.provider, await beacon.getAddress()),
      },
      {
        name: 'UpgradeableBeacon',
        address: await beacon.getAddress(),
      },
    );
    

    पूर्ण Code नमूना

    example.ts
    
    describe('Vault', () => {
      it('beacon proxy deployment and verification', async () => {
        const VaultFactory = await ethers.getContractFactory('Vault');
        const TokenFactory = await ethers.getContractFactory('TToken');
    
        let token = await ethers.deployContract('TToken');
        token = await token.waitForDeployment();
        const tokenAddress = await token.getAddress();
    
        await tenderly.verify({
          name: 'TToken',
          address: tokenAddress,
        });
    
        let beacon = (await upgrades.deployBeacon(VaultFactory)) as UpgradeableBeacon;
    
        await beacon.waitForDeployment();
        const beaconAddress = await beacon.getAddress();
    
        let vault = await upgrades.deployBeaconProxy(beacon, VaultFactory, [tokenAddress], {
          initializer: 'initialize',
        });
        await vault.waitForDeployment();
    
        console.log('Deployed beacon ', {
          proxy: beaconAddress,
          implementation: await getImplementationAddressFromBeacon(ethers.provider, beaconAddress),
          beacon: beaconAddress,
        });
    
        await tenderly.verify(
          {
            name: 'Vault',
            address: await getImplementationAddressFromBeacon(ethers.provider, beaconAddress),
          },
          {
            name: 'UpgradeableBeacon',
            address: beaconAddress,
          },
        );
    
        const vaultV2Factory = await ethers.getContractFactory('VaultV2');
    
        // upgrade
        vault = await upgrades.deployBeaconProxy(beacon, vaultV2Factory, [tokenAddress]);
    
        await upgrades.upgradeBeacon(beaconAddress, vaultV2Factory, {});
    
        console.log('Upgraded beacon ', {
          proxy: beaconAddress,
          implementation: await getImplementationAddressFromBeacon(ethers.provider, beaconAddress),
          beacon: beaconAddress,
        });
    
        await tenderly.verify({
          name: 'VaultV2',
          address: await getImplementationAddressFromBeacon(ethers.provider, beaconAddress),
        });
      });
    });