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

# Foundry के साथ proxy contracts verify करें

> forge script के साथ Virtual Environment पर एक UUPS implementation और उसके ERC1967 proxy को deploy और verify करें, फिर upgrade के बाद फिर से verify करें।

एक proxy deployment में दो contracts होते हैं: proxy, जो हर call को delegate करता है, और implementation, जो logic रखता है। दोनों को अलग-अलग verify किया जाना चाहिए। किसी भी proxy के लिए जो [ERC-1967](https://eips.ethereum.org/EIPS/eip-1967) का पालन करता है, Tenderly explorer standard implementation storage slot पढ़ता है, इसलिए एक बार दोनों contracts verify हो जाने के बाद, proxy address पर calls को implementation के ABI के साथ decode किया जाता है।

यह गाइड एक [Virtual Environment](/virtual-environments/overview) पर एक `ERC1967Proxy` के पीछे एक UUPS implementation (`CounterV1`) deploy करती है, दोनों को एक `forge script` run में verify करती है, implementation को `CounterV2` में upgrade करती है, और एक proxy को फिर से verify करना कवर करती है जो बिना verification के deploy किया गया था। Hardhat equivalent के लिए, देखें [Proxy Contracts को Verify करना](/contract-verification/hardhat-proxy)।

## शुरू करने से पहले

* [Deploy और verify contracts](/virtual-environments/develop/deploy-contracts) से setup पूरा करें: एक Virtual Environment, एक [funded deployer address](/virtual-environments/unlimited-faucet), और `cbor_metadata = true` तथा `bytecode_hash = "ipfs"` के साथ एक `foundry.toml`।
* environment variables सेट करें:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
export TENDERLY_VIRTUAL_TESTNET_RPC=...   # your Virtual Environment RPC URL
export TENDERLY_VERIFIER_URL=$TENDERLY_VIRTUAL_TESTNET_RPC/verify
export PRIVATE_KEY=...                    # deployer private key
```

* base library के साथ OpenZeppelin के upgradeable contracts स्थापित करें:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
forge install OpenZeppelin/openzeppelin-contracts --no-git --shallow
forge install OpenZeppelin/openzeppelin-contracts-upgradeable --no-git --shallow
```

* दोनों remappings को `remappings.txt` में जोड़ें:

```bash title="remappings.txt" theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
forge-std/=lib/forge-std/src/
```

दोनों libraries अलग-अलग भूमिकाएं निभाती हैं: `openzeppelin-contracts` proxy (`ERC1967Proxy`) प्रदान करता है, और `openzeppelin-contracts-upgradeable` implementation building blocks (`Initializable`, `UUPSUpgradeable`, `OwnableUpgradeable`) प्रदान करता है। upgradeable versions constructors को initializer functions से बदलते हैं, क्योंकि जब state proxy के पीछे रहती है तो constructors नहीं चलते।

## implementation contract

```solidity title="src/CounterV1.sol" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract CounterV1 is Initializable, OwnableUpgradeable, UUPSUpgradeable {
    uint256 public number;

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address owner_, uint256 initialNumber) external initializer {
        __Ownable_init(owner_);
        number = initialNumber;
    }

    function increment() external {
        number += 1;
    }

    function setNumber(uint256 newNumber) external {
        number = newNumber;
    }

    function version() external pure virtual returns (string memory) {
        return "v1";
    }

    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
```

इस contract के तीन भाग proxy pattern के लिए मायने रखते हैं:

1. `constructor() { _disableInitializers(); }` implementation को लॉक करता है। केवल proxy को state रखनी चाहिए; यह constructor implementation address पर direct `initialize` call को revert कर देता है।
2. `initialize(...)` constructor को replace करता है। proxy इसे एक बार delegatecall करता है, उसी transaction में जो proxy को deploy करता है।
3. `_authorizeUpgrade(...)` आवश्यक UUPS permissioning hook है। यह हर `upgradeToAndCall` पर चलता है; यदि यह revert होता है, तो upgrade block हो जाता है।

## deploy script

```solidity title="script/DeployProxy.s.sol" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Script, console} from "forge-std/Script.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {CounterV1} from "../src/CounterV1.sol";

contract DeployProxyScript is Script {
    function run() public {
        address owner = vm.addr(vm.envUint("PRIVATE_KEY"));
        uint256 initialNumber = 42;

        vm.startBroadcast();

        // 1. Deploy the implementation.
        CounterV1 implementation = new CounterV1();

        // 2. Deploy the proxy, calling initialize(owner, 42) in the same tx.
        bytes memory initData = abi.encodeCall(CounterV1.initialize, (owner, initialNumber));
        ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), initData);

        vm.stopBroadcast();

        console.log("Implementation:", address(implementation));
        console.log("Proxy         :", address(proxy));
        console.log("Owner         :", owner);
    }
}
```

script logic contract को deploy करती है, `abi.encodeCall` (जो `abi.encodeWithSignature` के विपरीत compile time पर arguments को type-check करता है) के साथ `initialize` calldata बनाती है, और proxy को deploy करती है। proxy का constructor implementation address को ERC-1967 implementation slot में store करता है और उसके विरुद्ध `initData` को delegatecall करता है, atomically proxy के storage को initialize करता है।

## दोनों contracts को deploy और verify करें

Proxy और implementation एक script में दो contracts हैं, इसलिए command किसी भी multi-contract deployment जैसा ही `forge script` आकार है:

```bash showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
forge script script/DeployProxy.s.sol:DeployProxyScript \
  --rpc-url        $TENDERLY_VIRTUAL_TESTNET_RPC \
  --private-key    $PRIVATE_KEY \
  --broadcast --slow \
  --verify \
  --verifier       custom \
  --verifier-url   $TENDERLY_VERIFIER_URL
```

Output का अपेक्षित अंत:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
##
Start verification for (2) contracts
Submitting verification for [src/CounterV1.sol:CounterV1] 0xeDa7...
	Response: `OK`
	Details: `Pass - Verified`
Submitting verification for [lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy] 0xb22e...
	Response: `OK`
	Details: `Pass - Verified`
All (2) contracts were verified!
```

दूसरे submission पथ पर ध्यान दें: proxy को `lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy` के रूप में verify किया गया है, आपके `lib/` tree से OpenZeppelin contract, `src/` में contract नहीं। Foundry इसे स्वचालित रूप से resolve करता है क्योंकि script का broadcast log प्रत्येक `new` और उसके bytecode को रिकॉर्ड करता है।

## proxy linkage की पुष्टि करें

Explorer proxy के माध्यम से calls को decode करता है जब proxy और implementation दोनों verify हों। यह पुष्टि करने के लिए कि proxy delegate कर रहा है, ERC-1967 implementation slot को सीधे पढ़ें:

```bash showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
PROXY=<your-proxy-address>
IMPL_SLOT=0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc

cast storage $PROXY $IMPL_SLOT --rpc-url $TENDERLY_VIRTUAL_TESTNET_RPC
# 0x000000000000000000000000<implementation address, 20 bytes>
```

फिर proxy के माध्यम से एक implementation function को call करें:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
cast call $PROXY "number()(uint256)" --rpc-url $TENDERLY_VIRTUAL_TESTNET_RPC
# 42
```

Tenderly Dashboard में, proxy के address page में verified `ERC1967Proxy` source, linked implementation address के साथ एक proxy tag, और एक ABI view दिखाई देता है जिसमें implementation के functions शामिल हैं। `proxy.increment()` या `proxy.setNumber(...)` को call करने वाले Transactions call trace में implementation के function names और parameter labels के साथ decode किए जाते हैं।

<Note>
  यदि explorer proxy को दिखाता है लेकिन implementation के ABI के साथ calls को decode नहीं करता, तो सबसे सामान्य कारण यह है कि दोनों contracts में से केवल एक verify है। जो भी छूट गया है उस पर फिर से `forge verify-contract` चलाएं।
</Note>

## implementation को upgrade करें

UUPS upgrades `upgradeToAndCall(newImpl, callData)` के माध्यम से जारी किए जाते हैं, जो `UUPSUpgradeable` से inherit होता है। एक V2 जोड़ें:

```solidity title="src/CounterV2.sol" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {CounterV1} from "./CounterV1.sol";

contract CounterV2 is CounterV1 {
    function decrement() external {
        number -= 1;
    }

    function version() external pure override returns (string memory) {
        return "v2";
    }
}
```

V2 लिखते समय Storage layout बाधाएं:

* V1 से inherit करें, या V1 के storage layout को verbatim copy करें। Storage slots positional हैं; एक मौजूदा state variable से पहले एक नया state variable जोड़ने से proxy का state corrupt हो जाता है।
* नए state variables V1 के मौजूदा variables के बाद जाते हैं, कभी बीच में नहीं।
* मौजूदा variable types को न बदलें या declarations को न reorder करें।

```solidity title="script/UpgradeProxy.s.sol" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Script, console} from "forge-std/Script.sol";
import {CounterV1} from "../src/CounterV1.sol";
import {CounterV2} from "../src/CounterV2.sol";

contract UpgradeProxyScript is Script {
    function run() public {
        address proxy = vm.envAddress("PROXY");

        vm.startBroadcast();

        CounterV2 newImplementation = new CounterV2();
        CounterV1(proxy).upgradeToAndCall(address(newImplementation), bytes(""));

        vm.stopBroadcast();

        console.log("New implementation:", address(newImplementation));
        console.log("Proxy upgraded:    ", proxy);
    }
}
```

इसे उसी verify flags के साथ चलाएं:

```bash showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
PROXY=<your-proxy-address> \
forge script script/UpgradeProxy.s.sol:UpgradeProxyScript \
  --rpc-url        $TENDERLY_VIRTUAL_TESTNET_RPC \
  --private-key    $PRIVATE_KEY \
  --broadcast --slow \
  --verify \
  --verifier       custom \
  --verifier-url   $TENDERLY_VERIFIER_URL
```

केवल `CounterV2` deploy और verify होता है (output `(1) contracts` की रिपोर्ट करता है)। proxy का address नहीं बदलता; केवल इसका ERC-1967 slot बदलता है। script return होने के बाद:

```bash showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
cast storage $PROXY $IMPL_SLOT --rpc-url $TENDERLY_VIRTUAL_TESTNET_RPC
# 0x000000000000000000000000<CounterV2 address>

cast call $PROXY "version()(string)" --rpc-url $TENDERLY_VIRTUAL_TESTNET_RPC
# "v2"

cast call $PROXY "number()(uint256)" --rpc-url $TENDERLY_VIRTUAL_TESTNET_RPC
# 42   <-- state preserved; only the logic changed
```

Explorer में proxy address अब `CounterV2` के ABI के विरुद्ध decode करता है। पुराना `CounterV1` implementation अपने मूल address पर verified रहता है लेकिन अब सक्रिय implementation नहीं है।

## एक proxy को verify करें जो पहले से deployed है

यदि आपने बिना `--verify` के deploy किया, तो प्रत्येक contract के लिए अलग से `forge verify-contract` चलाएं।

implementation `new CounterV1()` के माध्यम से बिना constructor arguments के deploy किया गया था, इसलिए किसी `--constructor-args` flag की आवश्यकता नहीं है:

```bash showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
forge verify-contract <IMPL_ADDRESS> src/CounterV1.sol:CounterV1 \
  --verifier       custom \
  --verifier-url   $TENDERLY_VERIFIER_URL \
  --watch
```

proxy को deploy समय पर उपयोग किए गए exact constructor arguments की आवश्यकता होती है, ABI-encoded:

```bash showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
# ABI-encode: constructor(address implementation, bytes initData)
INIT_DATA=$(cast calldata "initialize(address,uint256)" <OWNER_ADDRESS> 42)

forge verify-contract <PROXY_ADDRESS> \
  lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy \
  --verifier       custom \
  --verifier-url   $TENDERLY_VERIFIER_URL \
  --constructor-args $(cast abi-encode "constructor(address,bytes)" <IMPL_ADDRESS> $INIT_DATA) \
  --watch
```

सही करने के लिए तीन विवरण:

1. **contract path `lib/` location का उपयोग करता है**, `src/` नहीं। proxy OpenZeppelin का code है, इसलिए verifier जिस source से match करता है वह `lib/openzeppelin-contracts/...` में रहता है। `forge script --verify` इसे स्वचालित रूप से resolve करता है; `forge verify-contract` नहीं।
2. **`initData` को deploy-time `initData` से exactly match करना चाहिए।** भले ही deployment के बाद state बदल गई हो, constructor argument मूल `initialize(owner, 42)` calldata है जिसके साथ proxy bytecode बनाया गया था।
3. **proxy का constructor signature `(address, bytes)` है**, और `forge verify-contract` पहले से ABI-encoded रूप की अपेक्षा करता है, जो `cast abi-encode` उत्पन्न करता है।

## अगले कदम

* [Contracts deploy और verify करें](/virtual-environments/develop/deploy-contracts): Virtual Environment पर base Foundry और Hardhat verification flow।
* [Foundry का उपयोग करके Smart Contract Verification](/contract-verification/foundry): Tenderly के verification API के माध्यम से public networks पर contracts verify करना।
* [Proxy Contracts को Verify करना](/contract-verification/hardhat-proxy): UUPS, Transparent, और Beacon proxies के लिए Hardhat plugin flow।
