UUPS Proxies: Tutorial (Solidity + JavaScript)

Ah, I see, thanks for the clarification :+1:

How can I use

MarsV2 is Mars

and

MarsV3 is Mars

if Mars was already deployed in the blockchain?

Thank you for the great tutorial, the UUPSUpgradeable is only work with sol 0.8.2++? is there anyway to import it in the solc project that use 0.7? I cant find that smart contract in openzeppelin contract for v 0.7

Our contract will only work with the specified Solidity version. You can try copying the contract and adapting it for Solidity 0.7, but mind the risks of modifying the code.

await upgrades.upgradeProxy(myTokenV1.address, MyTokenV2)

Adding this to myToken test gives me an Ownable error. I pasted the final code into Remix and the owner function returns the 0x0 address.

Error: VM Exception while processing transaction: reverted with reason string 'Ownable: caller is not the owner'

After spending way too much time on this, I finally figured it out. The solidity code in the tutorial is missing the __Ownable_init(); function call in its initializer. Gonna leave my passing tests here for posterity.

// test/MyToken.test.ts

import { expect } from 'chai'
import { ethers, upgrades } from 'hardhat'
import { MyTokenV1 } from '../typechain/MyTokenV1'
import { MyTokenV2 } from '../typechain/MyTokenV2'

let myTokenV1: MyTokenV1
let myTokenV2: MyTokenV2

describe('MyToken', function () {
  it('deploys', async function () {
    const MyTokenV1 = await ethers.getContractFactory('MyTokenV1')
    myTokenV1 = (await upgrades.deployProxy(MyTokenV1, { kind: 'uups' })) as MyTokenV1
  })
  it('upgrades', async function () {
    const MyTokenV2 = await ethers.getContractFactory('MyTokenV2')
    myTokenV2 = (await upgrades.upgradeProxy(myTokenV1, MyTokenV2)) as MyTokenV2
  })
  it('adds with new function and variable', async function () {
    await myTokenV2.add(21)
    expect((await myTokenV2.num()).toString()).to.equal('21')
    await myTokenV2.add(21)
    expect((await myTokenV2.num()).toString()).to.equal('42')
  })
})
// contracts/MyTokenV2.sol

// SPDX-License-Identifier: MIT
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/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract MyTokenV2 is Initializable, ERC20Upgradeable, UUPSUpgradeable, OwnableUpgradeable {
    uint public num;

    function initialize() public initializer {
        __ERC20_init('MyToken', 'MTK');

        __Ownable_init();

        _mint(msg.sender, 1000 * 10**decimals());
    }

    function _authorizeUpgrade(address) internal override onlyOwner {}

    function add(uint _num) public {
      num += _num;
    }
}
1 Like

My bad, sorry about that! Thank you for debugging and finding out the cause. I've updated the code in the original post.