UUPS upgradable smart contract deployment

I don't see a very clear guide to deploy UUPS smart contract using Truffle although I find some tutorial [UUPS Proxies: Tutorial (Solidity + JavaScript)]. I try to write a UUPS contract and deploy successfully. But still not sure if my way is right.

:1234: Code to reproduce

MyToken.sol

pragma solidity >=0.4.22 <0.9.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

contract MyToken is Initializable, ERC20Upgradeable, OwnableUpgradeable, AccessControlUpgradeable, UUPSUpgradeable {
...}

contract MyTokenV2 is MyToken {
    function version() pure public returns (string memory) {
        return "version2";
    }
}

deploy_token_1.js

const MyToken = artifacts.require('MyToken');
const MyTokenV2 = artifacts.require('MyTokenV2');
const { deployProxy, upgradeProxy } = require('@openzeppelin/truffle-upgrades');

module.exports = async function (deployer) {
  await deployProxy(MyToken, ['My Token', 'TKN', '100000'], { deployer, initializer: 'initialize', kind: 'uups' });
  //const mytoken = await MyToken.deployed();
  //await upgradeProxy(mytoken.address, MyTokenV2, {deployer, kind: 'uups' });
  console.log("hello Mytoken1");
};

deploy_token_2.js

const MyToken = artifacts.require('MyToken');
const MyTokenV2 = artifacts.require('MyTokenV2');
const { deployProxy, upgradeProxy } = require('@openzeppelin/truffle-upgrades');

module.exports = async function (deployer) {
  //await deployProxy(MyToken, ['My Token', 'TKN', '100000'], { deployer, initializer: 'initialize', kind: 'uups' });
  const mytoken = await MyToken.deployed();
  await upgradeProxy(mytoken.address, MyTokenV2, {deployer, kind: 'uups' });
  console.log("hello Mytoken2");
};

I deploy the contract to Ganache localhost development

truffle migrate --network development

If I use deploy_token_1.js to deploy the contract, it works well. However, if changing to use the deploy_token_2.js,

truffle migrate --network development
...
...
...
Network up to date

Until I force to redeploy the upgradable contract by

truffle migrate --network development --reset

The UUPS contract can be deployed successfully.

My question:

  1. Should we set --reset to force deploying upgradabe contract each time?
  2. If negative answer for above, how to improve? contract code or deployment js code?

Thanks.

:computer: Environment

Truffle v5.5.1 (core: 5.5.1)
Ganache v7.0.1
Solidity - 0.8.11 (solc-js)
Node v16.14.0
Web3.js v1.5.3

1 Like

Hi @zqc, truffle migrate would only run new migration scripts that have been added since the previous run.

So for example, you could just create deploy_token_1.js by itself, and run truffle migrate --network development.
Then add deploy_token_2.js and run truffle migrate --network development again, and this will cause Truffle to only run the second script.

Note that the above is for migrations. If you want to test your contracts and their upgrade process instead, you can use Truffle tests -- see Truffle docs and an example with the Truffle Upgrades plugin.