Can't set the value of a variable when passing encoded data as parameter with upgradeable contracts

I posted many days ago and I thought to have understood the answers but apparently here I am asking the same questions again!

I have these contracts:

import "@openzeppelin/contracts/access/Ownable.sol";

contract Box is Ownable {
    uint256 public _x;
    bool private _initialized;
    string private _version;

    function initialize(uint256 x, string memory version) public {
        require(!_initialized, "Contract instance has already been initialized");
        _initialized = true;
        _x = x;
        _version = version;

    function getValueOfX() public view returns(uint256) {
        return _x;

    function versionOfContract() public view returns(string memory) {
        return _version;

    function isInitialised() public view returns(bool) {
        return _initialized;

    function setValueOfX(uint256 x) public {
        _x = x;

    function getTen() public pure returns(uint256) {
        return 10;

This is my proxy:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

contract MyProxy is TransparentUpgradeableProxy {
    constructor(address _logic, address _admin, bytes memory _data) TransparentUpgradeableProxy(_logic, _admin, _data) {}

And this is my admin:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
contract Admin is ProxyAdmin {
    constructor() ProxyAdmin() {}

I'm using hardhat to deploy the contracts on my local newtwork using this script:

const { ethers } = require("hardhat");

async function main() {
    // We get the contract to deploy
    const Box = await ethers.getContractFactory("Box");
    const Admin = await ethers.getContractFactory("Admin");
    const Proxy = await ethers.getContractFactory("MyProxy");

    [owner, addr1, addr2, ...addrs] = await ethers.getSigners();

    const box = await Box.deploy();
    const admin = await Admin.deploy();
    const iface = new ethers.utils.Interface(["function initialize(uint256 x, string memory version)"]);
    const encodedFunctionData = iface.encodeFunctionData(
    const proxy = await Proxy.deploy(box.address, owner.address, encodedFunctionData);

    console.log(`Address of proxy: ${proxy.address}, \nAddress of implementation: ${box.address}`);
    .then(() => process.exit(0))
    .catch((error) => {

So when I deploy my proxy I pass as the third parameter the encoded data that would initialize my implementation contract, right? No, wrong. To test if everything went smooth I'm using hardhat console like so:

 > npx hardhat console --network localhost
 > const d = await ethers.getContractFactory("Box")
 > const dd = d.attach("0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0")
 > await dd.getValueOfX()
 BigNumber { value: "0" }

So apparently my initialize function is not being called when I deploy the smart contract! It's been days now I'm trying to get it work but I can't. Please help me.


You don't have to deploy proxy/admin contracts manually, using the hardhat upgrades library you just deploy your contract with upgrades.deployProxy() ....
Its all well explained here.
Hope you work it out :+1:

Yes I know but I want to understand how to do that without the libraries

In that case check the binaries:

Is this the address of the proxy or the implementation? It needs to be the proxy. If it's the impementation, you will get 0.

It is the proxy, I'm sure

Ok, this may be because you're setting the proxy admin to be "owner", which is the same account that you're using to query getValueOfX. For security reasons, the proxy admin does not have access to the underlying implementation functions.

In this line:

const proxy = await Proxy.deploy(box.address, owner.address, encodedFunctionData);

Try changing owner.address to admin.address.