1

I'm currently playing around with Proxy Upgradability, and noticed the use of assembly in terms of the new upgraded contract and the slot assigned. Real implementation can be seen here.

I have broken this implementation down to understand what is happening:

pragma solidity ^0.5.0;

contract Base {

bytes32 internal constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;


function _setImplementation(address newImplementation) public {
   bytes32 slot = IMPLEMENTATION_SLOT;

   assembly {
     sstore(slot, newImplementation)
   }
}

function _implementation() public view returns (address impl) {
   bytes32 slot = IMPLEMENTATION_SLOT;
   assembly {
     impl := sload(slot)
   }
}

function getSlot() public view returns(bytes32) {
    return IMPLEMENTATION_SLOT;
}
}

Then created tests to see the results, and see what is modified etc...

const Base = artifacts.require("Base")

contract('Base', function(account) {

beforeEach(async function () {
    this.base = await Base.new();
})
describe('...', function () {
    describe('...', function () {
        it('check slot', async function () {
            console.log(await this.base.getSlot());
        })

        it('check slot', async function () {
            console.log(await this.base._implementation());
        })

        it('change slot', async function () {
            console.log(account[0]);
            await this.base._setImplementation(account[0]);
        })

        it('check slot', async function () {
            console.log(await this.base.getSlot());
        })

        it('check slot', async function () {
            console.log(await this.base._implementation());
        })

    })
})
})

Which gives the result:

0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3
    ✓ check slot
0x0000000000000000000000000000000000000000
    ✓ check slot
0x627306090abaB3A6e1400e9345bC60c78a8BEf57
    ✓ change slot (69ms)
0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3
    ✓ check slot
0x0000000000000000000000000000000000000000
    ✓ check slot

Why does the slot variable not change, and if that is not meant to change, why does ADMIN_SLOT not change either?

  • What made you think that initializing the local (non-state) variable slot with the value of the constant IMPLEMENTATION_SLOT, and then writing a different value into slot (whether you do it in assembly or not), would change the value of the constant IMPLEMENTATION_SLOT??? The variable slot does not reference the variable IMPLEMENTATION_SLOT as a result of slot = IMPLEMENTATION_SLOT! And in any case, did you actually expect to be able to change the value of a constant in the contract? Why o you think it's called "constant"? – goodvibration Jul 15 at 20:04
0

You are deploying a new instance before every test so any changes will be ignored in following tests

beforeEach(async function () {
    this.base = await Base.new();
})
  • Thanks :) Out of curiosity, how are we able to modify/retrieve the slot variable if it hasn't been declared out width of the functions scope? Random thought: Does sstore declare, and also store this in a global sense of the contract? – user54592 Jul 16 at 7:30
  • As stated by goodvibration you cannot access the local variables from outside the function scope where they were declared. The function sstore modifies the contract storage where global variables are stored, but it does not declare a new variable. – Ismael Jul 16 at 14:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy