Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storage compatibility: Solidity upgradable smart contract using "proxy" design pattern and changing the mapping type

Anyone used the "proxy" pattern to write upgradable smart contracts? I am planning to upgrade/extend my old smart contract, originally, my code looks like this:

mapping(address => uint256)  balance;

I am planning to write it like this:

struct PackedBalance {
    uint256 balance;
    uint256 locked_balance;    // to support a new feature.
}
mapping(address => PackedBalance) balance;

My concern is if the "storage" is compatible to the "old version smart contract".

I just read the "Layout of State Variables in Storage". As I understand it, it is compatible. But I am a newbie, so I would like to seek help from some experts.

"compatible" means: I can still read correct "balance" of the existing storage slots. And I can write "locked_balance" without breaking anything(like overwritten).

like image 823
Andy Jiang Avatar asked Mar 22 '26 05:03

Andy Jiang


1 Answers

Yes, it's safe to expand the uint256 within a mapping to the struct within the same mapping.

Lets debug these two example contracts:

pragma solidity ^0.8;

contract MyContract {
    mapping(address => uint256) balance;
    
    function setBalanceForAddress(address _address, uint256 _balance) external {
        balance[_address] = _balance;
    }
}
pragma solidity ^0.8;

contract MyContract {
    struct PackedBalance {
        uint256 balance;
        uint256 locked_balance;
    }

    mapping(address => PackedBalance) balance;
    
    function setBalanceForAddress(address _address, uint256 _balance, uint256 _lockedBalance) external {
        balance[_address] = PackedBalance(_balance, _lockedBalance);
    }
}

The address is always going to be 0x1231231231231231231231231231231231231231 (for debugging purposes).

The first contract stores the uint256 field to storage slot 0xf100689cc6bb188feb3c0ef4658bee6e8042e58e79daebcd84870d7f336a8422

Tx data:

0x4fa1007300000000000000000000000012312312312312312312312312312312312312310000000000000000000000000000000000000000000000000000000000000064

Remix debugger screenshot:

Remix debugger screenshot


The second contract stores the struct to slots 0xf100689cc6bb188feb3c0ef4658bee6e8042e58e79daebcd84870d7f336a8422 (same as the first contract) and 0xf100689cc6bb188feb3c0ef4658bee6e8042e58e79daebcd84870d7f336a8423 (right next to it).

Tx data:

0x6f7223d9000000000000000000000000123123123123123123123123123123123123123100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064

Remix debugger screenshot:

Remix debugger screenshot

like image 67
Petr Hejda Avatar answered Mar 24 '26 20:03

Petr Hejda