Full Smart Contract Upgradeability Discussion

I’m probably going a bit ahead of myself, but my question is: how actual migration and deployment of contract to the main net looks like and later interaction, is there a course that we actually deploying a proxy contract or any contract to the main net or test net(I guess the process of deploying contract to test net looks identical)? I’m asking because I see all those jobs offers for smart contract devs but they all require developer to have deployed contract that is working contract on the main net.

Hey @Kamil37, hope you are ok.

Almost at the end of the next course, there is a lesson on how to deploy on a live network (testnet). The process for main net is basically the same, but before going into the mainnet, all project are bullet proved in the testnet first.
https://academy.ivanontech.com/courses/ethereum-smart-contract-programming-201

Carlos Z

1 Like

Same boat as you brother.
Getting the error:
Builtin function "gas" must be called.

Just change gas to gas().
Same goes with returndatasize to returndatasize()

1 Like

Does anyone know how we’d go about including:
Structs, and arrays into these contracts?

I’m trying to incorporate this into a project which I have a deadline for super soon and I can’t wrap my head around it.

Any help/ideas would be super amazing. :cowboy_hat_face:

Hey @jak, hope you are ok.

I did not understand the question, if you want to know how to use structs and arrays, you should check the Ethereum Smart Programming 101 course.

Carlos Z

Thanks for the response.

I was moreso referring to referencing the storage contract, seeing as it just holds generic mappings - I was confused as to how you could extend functionality this idea to build structs and arrays on this upgradeable platform (seeing as they are not mappings.
But… I think I’ve got it now aha.
So thanks!

1 Like

I have a couple questions:

  1. We where taught we should not re-deploy the proxy contract but in the terminal when we migrate --reset doesn’t that re-deploys the proxy along with the updated functional contract? Is there a way to re-deploy without the proxy contract?

  2. Why are we using .new and not .deployed? does it matter which one?
    new

1 Like

hey @cecilia, hope you are well.

when you use migrate --reset it will deploy all the contracts that have a migration file, by only creating a migration file for the main contract, it will deploy it each time you call the migrate method, if you want to also deploy the proxy contract, you just have to also do a migration file for it.

.deployed is used when the migrate command is invoked and the migration files of each exists.
.new will create a new instance of the contract that will only exists while the unit test is running.

Carlos Z

1 Like

Thank you so much, I understand now. :slight_smile:

1 Like

My question is regarding this snippet from the migrations folder

//Fool truffle once again. It now thinks proxyDog has all functions.
  proxyDog = await DogsUpdated.at(proxy.address);
  //Initialize proxy state.
  proxyDog.initialize(accounts[0]);

Q. In the dogs contract when we are doing this :

constructor() public {
    initialize(msg.sender);
  }

Why do we then separately call the initialize function in the migrations when if it is already defined in the constructor ? Shouldn’t it run automatically ?

Thanks
Cheers

I want to share an interesting edit I made in fallback function :
@filip

So basically our pervious code was only forwarding functions to one contract, to make it more dynamic and have different functional contracts for different organisations/purposes I have used the calldatacopy() assembly opcode. Please have a look at the code and tell me what are your views

Note : Please inform me if you find a security vulnerability over here.

fallback() external payable {

//Setting variable for the data of the function 
//This is all the input values of the function
     bytes memory data = msg.data;

//Setting the proxy contract address
//My addition : 
bytes20 _address;

assembly {
        calldatacopy(0x0, 16, 36)
        _address := mload(0x0)
}

address proxy = address(_address);

//For security setting the condition that address is a one which we recognize
require(functionalAddress[proxy], "This is not an active proxy contract");

//The fun begins
assembly {
let result := delegatecall(gas(), proxy, add(data, 0x20), mload(data), 0, 0)
let size := returndatasize()
let ptr := mload(0x40)
returndatacopy(ptr, 0, size)

switch result
case 0 {revert(ptr, size)}
default {return (ptr, size)}
}
}

Hey guys,

I’m getting an error I don’t understand.

I’m refering to the assembly code in the Proxy contract. The error I’m getting is: Builtin function “gas” must be called. This has to do with the following line of code where the word gas is underlined in red:

let result := delegatecall(gas, implementation, add(data, 0x20), mload(data), 0, 0)

Does anyone know what it means or how to fix it. Googling it doesn’t show much, neither do the docs on inline assembly.

For some reason, the command prompt application freezes when I type “truffle develop”.

This is all the code of all the files I am using:

Storage.sol:

pragma solidity 0.5.1;

contract Storage {
  /* create a bunch of different mappings in case you need a specific type of Storage
  in the future */

  mapping (string => uint 256) _uintStorage;
  mapping (string => address) _addressStorage;
  mapping (string => bool) _boolStorage;
  mapping (string => string) _stringStorage;
  address public owner;
  bool public _initialized;
  
}

Functional.sol:

pragma solidity 0.5.1;

import "./Storage.sol";

contract Functional is Storage {

  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

  constructor() public {
    owner = msg.sender;

  }

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

  }
}

Proxy.sol:

pragma solidity 0.5.1;
import "./Storage.sol";

contract Proxy is Storage {

  address currentAddress;

  constructor(address _currentAddress) public {
    currentAddress = _currentAddress;
  }
  function upgrade(address _newAddress) public {
    currentAddress = newAddress;
  }

//fallback function
  function () payable external {
    //redirect to currentAddress
    address implementation = currentAddress;
    require(currentAddress != address(0));
    bytes memory data = msg.data;

    assembly {
      let result := delegatecall(gas, implementation, add(data, 0x20), mload(data), 0, 0)
      let size := returndatasize
      let ptr := mload(0x40)
      returndatacopy(ptr, 0, size)
      switch result
      case 0 {revert(ptr, size)}
      default {return(ptr, size)}
      //we are sending back the info to the user that called this.
    }
  }
}

2_deploy_proxy.js:

const Dogs = artifacts.require('Dogs');
//the program looks for the contract name, not the file, watch out for that.
const Proxy = artifacts.require('Proxy');

module.exports = async function(deployer, network, accounts){
  const dogs = await Dogs.new;
  const proxy = await Proxy.new(dogs.address);
  
}

Command prompt:

Microsoft Windows [Version 10.0.19043.1165]
(c) Microsoft Corporation. All rights reserved.

C:\Users\Denzel>cd/d E:\UpgCon\ProxyCon

E:\UpgCon\ProxyCon>truffle develop

I think you have an extra sign that should not be there.

I might have to see the entire code to understand it, but:
OR it is:
let result = ... OR let result: ...

Carlos Z

Are you using powershell? you could also try with CMD (windows command prompt), some times powershell does not work because it can’t run script commands.

Carlos Z

Hi thecil,

Thanks for responding.

Since the making of the tutorial Solidity has evolved. The word gas represents an opcode, which is now also referred to as a “builtin function”. Back in the day, in older versions, it was possible to ommit the parenthesis:

For opcodes that do not take arguments, the parentheses can be omitted.

However, this has changed and it appears that omitting parenthesis is no longer allowed. So I went and added the parenthesis making gas into gas() and that did the trick. The next line of code (let size := returndatasize) had the same error, so I continued with the same procedure and changed returndatasize to returndatasize(). And now my code is error free and lets me compile.

Regards
Em

1 Like

im using command prompt

Hi,

I’m referring to the section Smart Contract Upgradeability - Full Example - Part 10 - Fixing the Owner Issue.

Is there any way someone can beat us to initialising the owner from the Proxy contract if we deploy the code as is in the migrations file? In other words, we initialse the owner in the migrations file - is there any way someone can call the initialise function before us?

Hey guys,

The Proxy contract as it is written here has a public upgrade function. That means that anybody can change the currentAddress, which means anybody could sabotage the functionality.

Shouldn’t there be an onlyOwner modifier added to the Proxy contract that we can then add to the function header of upgrade()?

Regards
Em

Depending on the version of solidity you are using, you might have to use
let result := delegatecall(gas(), implementation, add(data, 0x20), mload(data), 0, 0)
let size := returndatasize()