I'm trying to use Proxies in Ethers.

My Solidity file:

//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; // to use via getContractFactory()

contract Test {
    string public constant message = "Hello, world!";

I will try to read message from a Proxy.

I see 2 options:

  1. Call message() on an instance of TransparentUpgradeableProxy (doesn't work)
  2. Call message() on an instance of Test attached to the Proxy's address (doesn't work)

My script:

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

describe("Test", function () {

  it("Should be able to read message from proxy", async function () {

    // Get Signer
    const signer = await hre.ethers.getSigner();

    // Get Contract Factories
    const Test = await ethers.getContractFactory("Test");
    const Proxy = await ethers.getContractFactory("TransparentUpgradeableProxy");

    // Deploy Contract
    const test = await Test.deploy();
    await test.deployed();

    // Deploy Proxy
    const proxy = await Proxy.deploy(test.address, signer.address, []);
    await proxy.deployed();

    // Attach Contract ABI to Proxy Address
    const proxy2 = await Test.attach(proxy.address);

    console.log(await test.message()); // to make sure it works
    try { console.log(await proxy.message()) } catch (err) { console.log(err.message) } // option 1
    try { console.log(await proxy2.message()) } catch (err) { console.log(err.message) } // option 2

Output: enter image description here


2 Answers 2


I figured it out.

Option 2 (attaching the Contract to the Proxy's address) is the right way.

It was failing for me, because of this line: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.5.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol#L122

Now, I'm calling message from a non-admin address, like this:

await proxy2.connect(nonAdmin).message()

And it works.


There's a couple of things going on here.

  1. To deploy a proxy you must actually initialize the logic address in the constructor. You should hence do something along the lines of

     contract Test is TransparentUpgradeableProxy {
          address _logic,
          address _admin_,
          bytes memory _data
       ) payable TransparentUpgradeableProxy(_logic, _admin, _data) {}

Where the _logic is the address of the contract you are trying to proxy. That should set you off on actually deploying a proxy

  1. As to await test.message() it does not work because the contract itself does not have a message function. I don't think solidity provides default getters and setters so you'd need to implement them yourself.
  • Test is the _logic contract, not the proxy. I'm already passing its address to the Proxy in my script.
    – antoniopgs
    Apr 17, 2022 at 19:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.