0

I need to store 1250 numbers 16 bits elements in an array.

Storing unit256 cost 20.000 gas units each (SSTORE opcode), which at 200gwei gas price, will cost around 4.5 ETH.

My understanding is that I may be able to use assembly to pack together 16 numbers into a single 256bit word, so I will only have to use 80 SSTORE opcodes.

How can I do that?

0

1 Answer 1

2

You don't need assembly, you can do it with Solidity.

Be careful, sometimes it is better to use uint256 anyway because of conversion costs and more complexity, which generate more costs than the savings. Always check your real costs.

Said that, see the example below for two techniques you can use to save some gas.

You can try the code by yourself using this repo I created ad hoc to support this kind of question.

// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;

struct PackedUint16 { uint256 word; }

library packedUint16 {
    
    function set(PackedUint16 storage self, uint16 value, uint8 index)
        public
    {
        self.word = self.word | uint(value) << index * 16;
    }

    function get(PackedUint16 storage self, uint8 index)
        public
        view
        returns (uint16)
    {
        return uint16(self.word >> (index * 16));
    }

}

contract pack {

    //
    // Mid costs (28.901 gas)
    //
    using packedUint16 for PackedUint16;

    PackedUint16 public myValue;
    
    function testPackedUint16() 
        public
    {
        myValue.set(10, 0);
        myValue.set(100, 1);
        myValue.set(1000, 2);
        myValue.set(10000, 3);
    }

    function readPackedUint16()
        public
        view
        returns (uint16, uint16, uint16, uint16)
    {
        return (myValue.get(0), myValue.get(1), myValue.get(2), myValue.get(3));
    }

    //
    // The most costly (88.443 gas)
    //
    uint public a;
    uint public b;
    uint public c;
    uint public d;

    function testUint256() 
        public
    {
        a = uint(10);
        b = uint(100);
        c = uint(1000);
        d = uint(10000);
    }

    //
    // Cheapest one (22.134 gas)
    //
    uint public packed;

    function testPacked()
        public
    {
        packed |= uint(10) << 0 * 16;
        packed |= uint(100) << 1 * 16;
        packed |= uint(1000) << 2 * 16;
        packed |= uint(10000) << 3 * 16;
    }

    function readPacked()
        public
        view
        returns (uint16, uint16, uint16, uint16)
    {
        return (uint16(packed >> 0), uint16(packed >> 16), uint16(packed >> 32), uint16(packed >> 48));
    }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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