Full Smart Contract Upgradeability Discussion

I think in this video we got rid of onlyOwner modifier from “setNumberOfDogs” because it is inherited from Dogs contract. So the whole initialization concept does not make sense. Dogs contract cannot have onlyOwner modifier in “setNumberOfDogs” because it would need also initialize function and would become the same contract as DogsUpdated. So something like this would be better:

Dogs:

pragma solidity 0.5.2;

import "./Storage.sol";

contract Dogs is Storage {
    constructor() public {
        owner = msg.sender;
    }

    function getNumberOfDogs() public view returns (uint256) {
        return _uintStorage["Dogs"];
    }

    function setNumberOfDogs(uint256 toSet) public {
        _uintStorage["Dogs"] = toSet;
    }
}

DogsUpdated:

pragma solidity 0.5.2;

import "./Dogs.sol";

contract DogsUpdated is Dogs {
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    constructor() public {
        //This function will not be called - because we are using delegatecall from proxy contract
        //But the attacker can easily call it and then change owner from DogsUpdated perspective
        //so to prevent that this function must be included
        initialize(msg.sender);
    }

    function initialize(address _owner) public {
        //Action can be performed only once
        require(!_initialized);
        owner = _owner;
        _initialized = true;
    }

    function setNumberOfDogs(uint256 toSet) public onlyOwner {
        _uintStorage["Dogs"] = toSet;
    }
}
2 Likes

Why in this mapping : mapping (string => uint256) _uintStorage;
do we use a string ?

1 Like

This mapping where string is used is useful when you don´t know beforehand what kind of integers you are gonna need in the future

When you need new variables later, you can create them with the help of this mapping using strings and pointing them to integers.

_uintStorage[“MaxOrders”] = 400;
_uintStorage[“Attempts”] = 5;
_uintStorage[“MinCharacters”] = 32;

etc… you can fit all kind of integers you need and can access them with their strings/names

3 Likes

Wouldn’t you have to then convert them to an integer to then use them?

1 Like

This section on Upgradeability was one of the best out of all courses/sections IMO but also one of the most challenging. Can anyone here recommend any good resources or smart contract examples of projects running on Mainnet ETH that seperate the logic, proxy, and storage in their contracts? Would love to see some examples of projects that have effectively set this up in their contract design.

Big thanks to Filip and everyone at Moralis for another very well put together course.

2 Likes

I have seen it before in another course. I believe an example where you would use a mapping within a mapping would be for approving an allowance of tokens to be managed by an exchange.

mapping(address => mapping(address => uint256)) public allowance;

The outer mapping would be the smart contract exchange address.
The inner mapping would be the addresses on that exchange and their value.

I’m still learning also so please don’t take what I say as 100% true :slight_smile:

2 Likes

Hi everyone,

I’m having two errors here.

  1. I’m trying to compile Truffle but appears error in the constructor.
    Warning: Visibility for constructor is ignored...
  2. Shows error in the compiler version. I updated node version and truffle version. I don’t know if that is the problem or what could be.
    "Source file requires different compiler version (current compiler is 0.8.16+commit.07a7930e.Emscripten.clang) - note that nightly builds are considered to be strictly less than the released version"


Also, these are the versions shown.

Hope someone can help me.

1 Like

hey can you share your github ill have a look. this is strange since you seem to have specified the correct version in your truffle config. also as the for constructor warning, you can ignore this since it is only a warning message and not an error

Hi !!

Thanks for replying. It’s strange because I closed everything and reopened VS code and now those errors have disappeared. However, now it shows other kind of errors.

I’m using the same versions as shown above.

Here is my repo at GitHub.
https://github.com/avisas/upgradeableContract

1 Like

The first errors, are the same which is a recommendation to specify the SPDX license of the contract.
Just have to add // SPDX-License-Identifier: UNLICENSED at the start of each contract.

next one is the public keyword on the constructor, which might not be needed. Same for DogsUpdated.

Last one, you forgot to specify the visibility at the upgrade function.

Once you have corrected all this errors, the last one is related to a recommendation on the fallback function for proxy contract, you can ignore it, still keep an eye that at the end, truffle notify you that all your contracts were compiled succesfully.

Hope this helps :nerd_face:

Carlos Z

Thanks for replying!!

Errors solved. :smiley:
Now I’m deploying but only execute the first file on migration’s folder. It doesn’t execute 2_deploy_proxy.sol.
What I’m doing wrong?

1 Like

I have run migrate and it does deploy it for me, I encounter a revert error in the process, I advice to use an error message to know which is being triggered.

example:
require(currentAddress != address(0), "fallback: cant be zero address");

Carlos Z

1 Like

I added that part to the proxy.sol file but it continues with the same problem. :frowning:
What else can I do?

1 Like

I’m not sure why its not working for you properly.
You have not made any big change in your code rather than the version of the solidity.

I’m using pragma solidity 0.8.13; for all your contracts, I’m using your old migration file for proxy which is:

// grab from our source file
const Dogs = artifacts.require('Dogs');
const Proxy = artifacts.require('Proxy');
const DogsUpdated = artifacts.require('DogsUpdated');

module.exports = async function(deployer, network, accounts) {
    // type truffle deployment logic
    const dogs = await Dogs.new();
    const proxy = await Proxy.new(dogs.address);

    // dog contract is located at this address => (proxy.address)
    //to believe that proxy contract is Dog. ProxyDog to fool Truffle
    var proxyDog = await Dogs.at(proxy.address); 
    // set # of dogs through the proxy
    await proxyDog.setNumberOfDogs(10);

    //tested
    var nrOfDogs = await proxyDog.getNumberOfDogs();
    console.log("Before update: " + nrOfDogs.toNumber());

    //Deploy new version of Dogs
    const dogsUpdated = await DogsUpdated.new();
    proxy.upgrade(dogsUpdated.address);

    //Fool truffle once again. it thinks proxyDog has all dogsUpdated functions.
    proxyDog = await DogsUpdated.at(proxy.address);
    // Initialize proxy state
    proxyDog.initialize(accounts[0]); // 1st address - own address

    // check that storage remained
    nrOfDogs = await proxyDog.getNumberOfDogs();
    console.log("After update: " + nrOfDogs.toNumber());

    //Set the nr of dogs through the proxy with NEW FUNC CONTRACT
    await proxyDog.setNumberOfDogs(30);
}

Try to delete the folder build, it will be created again by truffle once it compiles the contracts. (that folder its created every time you compile, so it is common to delete if you want a fresh new compiled files).

Carlos Z

1 Like

It’s strange but I suppose everything is fine with my code.
I don’t know what else can I do to solve that problem.
I’ll keep it in that way.
Thanks :slight_smile:

1 Like

I’m in “Part 2 - Building a New Storage Contract” and using Atom.

the video shows that the code should be having colored below:

However, my code is only white as below:

Does it mean the environment is not reading my code? What am I not doing correctly?

I have tried to “truffle compile” my code in powershell but fail as below:

What should I do?

Probably its just the plugin for atom to highlight the syntax.

Should be this one: https://atom.io/packages/language-solidity

Executing scripts like nodeJs might require admin permissions, try to open powershell as administrator.

Carlos Z

1 Like

Thanks for the reply.

I’ve tried to run Powershell as Admin but have no idea how to open files as admin, so I use command prompt instead. Then I tried to truffle compile them.

Shown as in the image below, it said “Compiling .\contracts\Migrations.sol”. But it never say it’s compiling my Dog.sol, Proxy.sol, and Storage.sol as shown in the video. Is it normal?

The image below shows that only 1_initial_migration.js migrates, but 2_deploy_proxy doesn’t migrate. What am I missing?