Keep fixed-width heads separate from variable-sized payloads.
LET’S PICTURE IT
An index card points to a longer attachment instead of squeezing the attachment into the card.
SEE IT FOR YOURSELF
Follow a dynamic string from head to tailStep 1 / 4
This example encodes one string parameter with value hello. A dynamic argument uses an offset in its head, even when it is the only argument.
This example encodes one string parameter with value hello. A dynamic argument uses an offset in its head, even when it is the only argument.At argument byte 32, the string tail begins with length five. This counts the UTF-8 payload bytes and excludes all padding.At argument byte 64, read 68 65 6c 6c 6f for hello. Twenty-seven following zero bytes fill the final content word.The encoding uses ninety-six argument bytes: one offset word, one length word and one padded content word. A normal function call adds a four-byte selector before these bytes.
Animated local teaching model. No wallet, RPC or live blockchain data. Some labels and hashes are abbreviated for readability.
Classify the fields first
Consider uint256 and string together. The integer goes directly in the head. The string is dynamic, so its head entry contains an offset to a separate tail.
Measure the whole head
For values 7 and hello, the head occupies two words: sixty-four bytes. The string offset is therefore 64, measured from the start of this argument tuple.
Read the attachment
At byte 64, the tail begins with the string byte length, five. The UTF-8 bytes follow and zeros fill the remainder of their final thirty-two-byte word.
Separate framing from layout
A function selector, when present, sits before this argument tuple. Its four bytes do not get added to the stored offset. The offset still uses the tuple start.
Trace a local example
types: uint256,string
values: ["7","hello"]
no function selector prefix
word 0 · argument offset 0 bytes
0x0000000000000000000000000000000000000000000000000000000000000007
word 1 · argument offset 32 bytes
0x0000000000000000000000000000000000000000000000000000000000000040
word 2 · argument offset 64 bytes
0x0000000000000000000000000000000000000000000000000000000000000005
word 3 · argument offset 96 bytes
0x68656c6c6f000000000000000000000000000000000000000000000000000000
Word zero is 7; word one points to argument byte 64.