# How optimize array of uints in function call input arguments to decrease msg.data size?

I have a Solidity function like `sampleFunction(uint[]calldata)` which takes an array of `uint`s which contains 6 numbers `[1900000000000000,1,990,990,2,1]`. Far as I know these input variables will consume a `byte32` by each which leads to a lot of zeros in the call message data, therefore it is inefficient in terms of gas usage. My question is what can I do to save gas on the unwanted zeros? How can I create a shorter call message? My first idea was creating a string from the numbers but Solidity can't access string objects by index like it can be done in Python for example. What I want to achieve is something like the below example:

From this:

``````00000000000000001900000000000000
00000000000000000000000000000001
00000000000000000000000000000990
00000000000000000000000000000990
00000000000000000000000000000002
00000000000000000000000000000001
``````

To this:

``````00000001900000000000000199099021
``````

I am not familiar with the bytes representation of transaction data, but this is something what I would like send then unpack it in Solidity without using Assembly if it's possible.

• It is difficult to recommend something without more details about what represent each number. In the worst case you will be trading "calldata cost" against the cost of decoding the numbers. Parsing an array of bytes is not free.
– Ismael
Mar 16 at 5:38

To clarify, your array example appears to use numbers in decimal format, and your packing example also shows decimals. However, it is hexadecimal, so you can pack significantly larger numbers.

You have two ways to effectively pack the numbers into a single `uint256`/`bytes32`.

#### Decimal Packing

1. Packing: Choose a base (a power of 10) for each number. For example, if your number could be a maximum of 99, the base would be 100; for a maximum of 999, it would be 1000. The maximum for a single `uint256` number is:
``````0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
115792089237316195423570985008687907853269984665640564039457584007913129639935
``````

This allows for `77` digits to be arranged for your numbers. For example, with 3 numbers:

If `p = x1 * x2Base * x3Base + x2 * x3Base + x3` with `x1=1900000000000000, x2=1, x3=990`, and the bases `x2Base=10, x3Base=1000`, the maximums are `x2Max=9, x3Max=999`. However, you could choose other maximums depending on your case.

The packed number would then be: `1900000000000000 * 10 * 1000 + 1 * 1000 + 990 = 19000000000000001990`.

1. Decimal Unpacking: Use the `%` and `/` operators to extract the digits before and after the target number:
• Divide to remove the trailing digits.
• Use the modulo operation to extract the number.
``````x1 = p / (x2Base * x3Base)
x2 = (p % (x2Base * x3Base)) / x3Base
x3 = p % x3Base
``````
• We don't apply the modulo operation for `x1` because, after dividing, it is already our target (no numbers before it).
• We don't shift for `x3` because the number is already at the end.

#### Bitwise Packing

The `uint256` number has 32 bytes, and you can represent the numbers from the example above as `uint64`, `uint4`, `uint10`, etc.

1. Packing:
``````p = (x1 << (x2Size + x3Size)) | (x2 << x3Size) | x3
``````

With `x2Size=4, x3Size=10`, the packed number is `(1900000000000000 << (4 + 10)) | (1 << 10) | 990 = 31129600000000002014`.

1. Unpacking:
• Shift right to remove the trailing digits.
• Perform a bitwise AND to extract the number.
``````x1 = p >> (x2Size + x3Size) = 31129600000000002014 >> (4 + 10) = 1900000000000000
x2 = (p >> x3Size) & (2 ** x2Size - 1) = (31129600000000002014 >> 10) & (2**4 - 1) = 1
x3 = p & (2**x3Size - 1) = 31129600000000002014 & (2**10 - 1) = 990
``````
• We don't apply AND for `x1` as after shifting, it is already our target (no numbers before it).
• We don't shift for `x3` because the number is already at the end.

Made some tests on gas consumption: calldata.spec.ts, and with bitwise packing you would save `1968` GAS compared to `unit[] calldata`, if we assume 50gwei for the gas price, then it would cost 0.0000984ETH, that by 3.3K\$ makes `0.32\$` saving.