Questions on upgradeable contracts and events

I’m pretty sure that I know the answers but to avoid my head exploding if I’m wrong . . . .

A few of simple questions on upgradeable contracts and events:

  1. I have an upgradeable contract with events. I grab MY_ABI from “solc filename.sol --abi”.
    Am I correct in assuming that the following is correct and works?
    var EventSrcContract = web3.eth.contract(MY ABI);
    var EventSrc = EventSrcContract.at(‘CONTRACT ADDRESS’);

  2. I change my contract. Assuming that an event declaration is a variable and I know not to rearrange it
    Am I correct in assuming that the old EventSrc will work?

  3. The upgraded contract has another new event. I assume that the old EventSrc can’t see it. I assume that an EventSrc generated with the new ABI can see it. Am I correct in these assumptions?

Thanks! Mark

1 Like

Hi @MWaser

Yes.

You may want to look at the Interacting Programmatically guide and using OpenZeppelin Contract Loader.

Yes.

Though as far as I am aware events don't impact contract storage (for upgradeable contracts). I will confirm on this topic: Using events in upgradeable contracts?

I assume so too.


To try this out, I created a project for the Box contract

Box.sol

// contracts/Box.sol
pragma solidity ^0.5.0;

contract Box {
    uint256 private value;

    // Emitted when the stored value changes
    event ValueChanged(uint256 newValue);

    // Stores a new value in the contract
    function store(uint256 newValue) public {
        value = newValue;
        emit ValueChanged(newValue);
    }

    // Reads the last stored value
    function retrieve() public view returns (uint256) {
        return value;
    }
}

Deploy

Using OpenZeppelin CLI 2.8 Release Candidate deploying to ganache-cli

$ npx oz deploy
✓ Compiled contracts with solc 0.5.16 (commit.9c3226ce)
? Choose the kind of deployment upgradeable
? Pick a network development
? Pick a contract to deploy Box
✓ Added contract Box
✓ Contract Box deployed
All implementations have been deployed
? Call a function to initialize the instance after creating it? No
✓ Setting everything up to create contract instances
✓ Instance created at 0xCfEB869F69431e42cdB54A4F4f105C19C080A601
0xCfEB869F69431e42cdB54A4F4f105C19C080A601

Interact

$ npx oz send-tx
? Pick a network development
? Pick an instance Box at 0xCfEB869F69431e42cdB54A4F4f105C19C080A601
? Select which function store(newValue: uint256)
? newValue: uint256: 42
✓ Transaction successful. Transaction hash: 0x9f007d7f0fcb278a979fafecfceb45a9190b707bb8a0c08a90ce33a16e5feaff
Events emitted:
 - ValueChanged(42)

In a separate project (based on Interacting Programmatically guide)
Install web3 and OpenZeppelin Contract-Loader

$ npm install web3 @openzeppelin/contract-loader

JavaScript to get past events

// src/index.js
const Web3 = require('web3');
const { setupLoader } = require('@openzeppelin/contract-loader');

async function main() {
    // Set up web3 object, connected to the local development network, and a contract loader
    const web3 = new Web3('http://localhost:8545');
    const loader = setupLoader({ provider: web3 }).web3;

    // Set up a web3 contract, representing our deployed Box instance, using the contract loader
    const address = '0xCfEB869F69431e42cdB54A4F4f105C19C080A601';
    const box = loader.fromArtifact('Box', address);

    box.getPastEvents('ValueChanged', {
        fromBlock: 0,
        toBlock: 'latest'
    }, function(error, events){ console.log(events); });
    
}

main();

Copy build/contracts from other project

Run script

$ node ./src/index.js
[ { logIndex: 0,
    transactionIndex: 0,
    transactionHash:
     '0x9f007d7f0fcb278a979fafecfceb45a9190b707bb8a0c08a90ce33a16e5feaff',
    blockHash:
     '0xa4e5a458f7e8f88016f90455beb4daa4e47b4618d16b7de648e536a3be64e383',
    blockNumber: 4,
    address: '0xCfEB869F69431e42cdB54A4F4f105C19C080A601',
    type: 'mined',
    id: 'log_bc7583d8',
    returnValues: Result { '0': '42', newValue: '42' },
    event: 'ValueChanged',
    signature:
     '0x93fe6d397c74fdf1402a8b72e47b68512f0510d7b98a4bc4cbdf6ac7108b3c59',
    raw:
     { data:
        '0x000000000000000000000000000000000000000000000000000000000000002a',
       topics: [Array] } } ]

Box.sol (updated)

Add an additional event

// contracts/Box.sol
pragma solidity ^0.5.0;

contract Box {

    uint256 private value;

    // Emitted when the stored value changes
    event ValueChanged(uint256 newValue);
    event ValueChanging(uint256 oldValue, uint256 newValue);

    // Stores a new value in the contract
    function store(uint256 newValue) public {
        emit ValueChanging (value, newValue);
        value = newValue;
        emit ValueChanged(newValue);
    }

    // Reads the last stored value
    function retrieve() public view returns (uint256) {
        return value;
    }
}

Upgrade

$ npx oz upgrade
? Pick a network development
✓ Compiled contracts with solc 0.5.16 (commit.9c3226ce)
✓ Contract Box deployed
All implementations have been deployed
? Which instances would you like to upgrade? Choose by address
? Pick an instance to upgrade Box at 0xCfEB869F69431e42cdB54A4F4f105C19C080A601
? Call a function on the instance after upgrading it? No
✓ Instance upgraded at 0xCfEB869F69431e42cdB54A4F4f105C19C080A601. Transaction receipt: 0xcd85e8481c8e15f37a2822e5ac829cec315484dc8cddde37625270358ff9370f
✓ Instance at 0xCfEB869F69431e42cdB54A4F4f105C19C080A601 upgraded

Interact

$ npx oz send-tx
? Pick a network development
? Pick an instance Box at 0xCfEB869F69431e42cdB54A4F4f105C19C080A601
? Select which function store(newValue: uint256)
? newValue: uint256: 23
✓ Transaction successful. Transaction hash: 0x3e607e53c9ff6d8831673840d6edc99e44cb7d75b52f469a7704300c7097d028
Events emitted:
 - ValueChanging(42, 23)
 - ValueChanged(23)

Run script

Without updating artifacts in project, run script

$ node ./src/index.js
[ { logIndex: 0,
    transactionIndex: 0,
    transactionHash:
     '0x9f007d7f0fcb278a979fafecfceb45a9190b707bb8a0c08a90ce33a16e5feaff',
    blockHash:
     '0xa4e5a458f7e8f88016f90455beb4daa4e47b4618d16b7de648e536a3be64e383',
    blockNumber: 4,
    address: '0xCfEB869F69431e42cdB54A4F4f105C19C080A601',
    type: 'mined',
    id: 'log_bc7583d8',
    returnValues: Result { '0': '42', newValue: '42' },
    event: 'ValueChanged',
    signature:
     '0x93fe6d397c74fdf1402a8b72e47b68512f0510d7b98a4bc4cbdf6ac7108b3c59',
    raw:
     { data:
        '0x000000000000000000000000000000000000000000000000000000000000002a',
       topics: [Array] } },
  { logIndex: 1,
    transactionIndex: 0,
    transactionHash:
     '0x3e607e53c9ff6d8831673840d6edc99e44cb7d75b52f469a7704300c7097d028',
    blockHash:
     '0x65c9aa204213922c0db2afe8c45625eb5905b06a2332bfd20576a677eca5dac0',
    blockNumber: 7,
    address: '0xCfEB869F69431e42cdB54A4F4f105C19C080A601',
    type: 'mined',
    id: 'log_8120791b',
    returnValues: Result { '0': '23', newValue: '23' },
    event: 'ValueChanged',
    signature:
     '0x93fe6d397c74fdf1402a8b72e47b68512f0510d7b98a4bc4cbdf6ac7108b3c59',
    raw:
     { data:
        '0x0000000000000000000000000000000000000000000000000000000000000017',
       topics: [Array] } } ]

Change script to get events for ValueChanging event and get an error

$ node ./src/index.js
(node:14909) UnhandledPromiseRejectionWarning: Error: Event "ValueChanging" doesn't exist in this contract.

Copy artifacts and rerun

$ node ./src/index.js
[ { logIndex: 0,
    transactionIndex: 0,
    transactionHash:
     '0x3e607e53c9ff6d8831673840d6edc99e44cb7d75b52f469a7704300c7097d028',
    blockHash:
     '0x9dec8e13054fba7872c5e56bd5ed354dfb97c798f1a8151682b06dced9156011',
    blockNumber: 7,
    address: '0xCfEB869F69431e42cdB54A4F4f105C19C080A601',
    type: 'mined',
    id: 'log_a08093e6',
    returnValues:
     Result { '0': '42', '1': '23', oldValue: '42', newValue: '23' },
    event: 'ValueChanging',
    signature:
     '0x737c5296e2c8ee4fe448f01f4b31dc800ecc70702e1f71a3d02d02eb441d5fb2',
    raw:
     { data:
        '0x000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000017',
       topics: [Array] } } ]

Freakin’ AWESOME!

I’m a Solidity newbie so it never even occurred to me that there is an easy interface to get past events (maybe it should have). That is going to help a lot.

1 Like

Heh. It took me a while to figure out that you could copy the artifacts because you were using two projects. Miss a single line of instructions and . . . .

1 Like

Sorry that I wasn’t clearer on my write up. Will have that in mind for the next answer.

Keep the questions coming.

I marked my answer as the solution.

I’ve run into a snag.

Above you’re using the OpenZeppelin CLI 2.8 Release Candidate and npx oz deploy.

When we’re deploying to Azure, we’re using CLI Byzantium version, solc version 0.5.3 and npx oz create.

Will the old CLI and create work? If not, what should I try?

(I’m moving towards trying it – but I figured you might know off the top of your head another sequence that I might have to use . . . . :wink: )

1 Like

Hi @MWaser,

You can use oz create in OpenZeppelin CLI 2.7 to deploy upgradeable contracts (Prior to OpenZeppelin CLI 2.8 the CLI only supported deploying upgradeable contracts). Everything else should be the same.

Hi @abcoathup,

So using [CLI Byzantium version, solc version 0.5.3 and npx oz create] should work?

I’m about to quit for the day – but I’ll try it tomorrow on the Azure.

Thanks!

1 Like

Hi @MWaser,

Yes it should work, (though I haven’t tried). Let me know if you have any issues.

I also suggest looking at changing the EVM version of the PoA network so that you can more easily use the latest tools.

:wink: Yeah, if I could figure out ow to change the EVM, I certainly would. I’ve been trying to chase it down with my Azure rep – but he seems to be spinning his wheels. I’ll let you know if I discover anything useful. :wink:

1 Like