2

In one uint256 I want to store the entire sender's address of 20 bytes and then 12 bytes of a second address. In this case the example addresses will be the following:

0x9E1C3a90c6EB03F914dF819CA9b3c891DE003301 sender address

0xdFd6b3Fd6E13C3E6AE53d510bFAb5217b5b39FeC secondary / other address

I send a tx with the setCharacter function below.

setCharacter(0xdFd6b3Fd6E13C3E6AE53d510bFAb5217b5b39FeC, 25)

Now when I use the getter to retrieve the data I get the following.

getCharacter(25)
owner_address -> 0x9E1C3a90c6EB03F914dF819CA9b3c891DE003301
secondpart -> 0

The secondpart = 0 is not what I am shooting for. I want secondpart to be equal to the equiv of 0xAE53d510bFAb5217b5b39FeC (last 12 bytes of 2nd address) or 0xdFd6b3Fd6E13C3E6AE53d510 (first 12 bytes of the 2nd address). Any pointers on where I went wrong? Thank you for any help.

contract storagetest8 {

    mapping(uint256 => uint256) inventories;

    function setCharacter(address other_address, uint256 index1) 
        external 
    {
        uint256 _id = uint256(msg.sender);
        _id |= uint96(other_address)<<160;
        inventories[index1] = _id;        
    }


    function getCharacter(uint256 index1) 
        external view
    returns(address owner_address, uint256 secondpart) {
        uint256 _id = inventories[index1];
        owner_address = address(_id);
        secondpart = uint256(uint96(_id>>160));
    }

}
3

Here is a fix and there's no need for the uint96 cast since you need to cast again to uint256.

contract storagetest8 {

    mapping(uint256 => uint256) inventories;

    function setCharacter(address other_address, uint256 index1) 
        external 
    {
        uint256 _id = uint256(msg.sender);
        _id |= uint256(other_address)<<160;  // fix
        inventories[index1] = _id;        
    }


    function getCharacter(uint256 index1) 
        external view
    returns(address owner_address, uint256 secondpart) {
        uint256 _id = inventories[index1];
        owner_address = address(_id);
        secondpart = _id>>160;  // simplified
    }
}

Explanation: In the question, the line in setCharacter could be fixed to: _id |= uint256(uint96(other_address))<<160; Need to cast the 96 bit value back to 256 bits before shifting, because left shifting a 96 bit value by 160 bits equals zero. But may as well keep using 256 bits.


When testing in Remix, I had to quote the address "0xdFd6b3Fd6E13C3E6AE53d510bFAb5217b5b39FeC", 25 when invoking setCharacter.

The result is secondpart 53951738724962035537443790828 which is 0xAE53d510bFAb5217b5b39FeC

  • What does =| do? @eth – alper Apr 23 at 19:04
  • 1
    @alper | is bitwise OR. a |= b is shorthand for a = a|b. – eth May 25 at 8:37
2

I have introduced the notion of Micro slots, whilst this is still in the early stages, it does allow you to store multiple values in a single uint256 slot. I want to compare the gas costs of using Micro slots with that of using Bitwise shifting to determine which one is more efficient. I just have not got around to this as yet. Here is a simple example of how this would work in a Solidity contract. Obviously the functions which "get" and "set" the Micro slots would need some validation (to avoid underflow & overflow) and perhaps some event logs emitted etc. This is just a prototype which I hope can move forward as a design pattern for the community to use. For this reason I have opened this Informational EIP.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.