How to use TransparentUpgradeableProxy as Transparent Proxy

2k views Asked by At

I'm Solidity Newbie.

I'm learning how to implement Transparent Proxy using Openzeppelin's TransparentUpgradeableProxy contract, but am having some problems.

Step 1: I tried to deploy a simple contract MyConV0, then implemented deploy and call method, everything is fine.

// File MyConV0.sol
pragma solidity ^0.8.0;

import "hardhat/console.sol";

contract MyConV0 {    
    string private _name;
    string private _symbol;

    constructor(string memory name_, string memory symbol_) public {            
      _name = name_;
      _symbol = symbol_;    
      console.log(_symbol);
    }
    
    function symbol() public view returns (string memory) {
        console.log(_symbol);
        return _symbol;
    }

    function name() public view returns (string memory) {
        console.log('Name: ');
        console.log(_name);
        return _name;
    }

    function getVersion() pure external returns(uint256) {
        return 0;
    }    
}

Step 2: I tried to upgrade to MyConV1 to be able to Upgradable with TransparentUpgradeableProxy but failed.

// File: MyConV1
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "hardhat/console.sol";

contract MyConV1 is Initializable, OwnableUpgradeable {   
    string private _name;
    string private _symbol;

    function initialize(string memory name_, string memory symbol_) initializer public {      
      __Ownable_init();
      _name = name_;
      _symbol = symbol_;
      
      console.log(_symbol);
    }

    
    function symbol() public view returns (string memory) {
        console.log('Symbol: ');
        console.log(_symbol);
        return _symbol;
    }

    function name() public view returns (string memory) {
        console.log('Name: ');
        console.log(_name);
        return _name;
    }

    function getVersion() pure external returns(uint256) {
        return 1;
    }
    
}

Refer TransparentUpgradableProxy: https://docs.openzeppelin.com/contracts/4.x/api/proxy#TransparentUpgradeableProxy

// The test file in JS using ethers.js and Hardhat environment
async function main() {

  let t0, t1, t2, t3, t4, v1, v2, v3, v4;
  
  const [owner, proxyAdmin, user, other] = await ethers.getSigners();
  
  // --- 0. Deploy MyConV0
  let input0 = [ 'TotoName', 'Toto' ];
  let con0 = await deploy_verify_contract("MyConV0", input0);  
  t0 = await con0.symbol() ;
  console.log(t0); // worked -> Toto

  // --- 1. Deploy MyConV1
  let input1 = [ ];
  let con1 = await deploy_verify_contract("MyConV1", input1);  


   // --- 2. get data
  let abi = [ `function initialize(   string name_,
                                      string symbol_,                                      
                                  )` ];
  let iface = new ethers.utils.Interface(abi);
  let data = iface.encodeFunctionData("initialize", [ 'TotoName', 'Toto' ]);  
  
  
  // --- 3. deploy trans proxy
  let input2 = [ con1.address, owner.address, data ];  
  let con2 = await deploy_verify_contract("TransparentUpgradeableProxy1", input2);  

  // --- 4. call proxy method
  t2 = await con2.implementation();
  console.log(t2); // DO NOT WORK, t2 is object tx, and do not contains the results like step 0

  // --- 5. call MyConV1 contact via proxy -> ERROR: "TypeError: con2.symbol is not a function"
  t3 = await con2.symbol();
  console.log(t3);

}

async function deploy_verify_contract(contractName, input, lib = {}){
  
  const _contract = await hre.ethers.getContractFactory(contractName, lib);
  const contract = await _contract.deploy(...input);

  await contract.deployed();

  console.log( contractName + " deployed to:", contract.address );

  return contract;

}

I used Hardhat's console.log function and it seems to have successfully deployed the Proxy, and sent the correct data to the MyConV1.initialize function, but don't know how to call the proxy properly. Specifically with the above code, I don't understand a few points:

  • Have I deployed the proxy correctly?
  • Why can't I get the correct return data of the proxy's implementation() function?
  • Why can't I call MyConV1's function through the proxy?

Hope you guys can help me how to correct the code, I have not been able to solve this problem for a few days.

1

There are 1 answers

0
tur461 On

You are not calling UpgradeTo() on proxy contract to set the implementation contract's address. After you have set the implementation contract in proxy you have to initialise the implementation contract via proxy contract only! not any other way or directly calling it on implementation contract (it wont work!!)