Metadata Standard
Deep dive the Patchwork metadata standard
Patchwork uses a metadata format which allows for discoverability, lower gas usage and efficiency reading and writing field sets on and off chain.
Metadata packing is performed by the PDK code generator but may be done in other ways as long as packing rules are followed.
Onchain Schemas
Contracts supporting onchain Patchwork metadata must implement the schema()
function as documented below
A schema()
call must return a MetadataSchema
as specified here:
Currently supported field types are:
Fields may be specified in any order so long as the rules below are adhered to
Rules
- IDs must be unique
- Keys must be unique
- Field slots and offsets must be accurately described in the schema
- Fields, including arrays, than span multiple slots must start at an offset of 0 in the first slot. Spanned slots must be contiguous and must not have any other fields specified in overlapping space of the contiguous slot space.
- Dynamic fields, such as dynamic length arrays and dynamic length strings, may not be packed into static metadata but must be in separate storage.
- Dynamic fields, such as dynamic length arrays and dynamic length strings, must be marked slot 0, offset 0, length 0 in the schema
- Individual fields that are not arrays must be marked as length 1 in metadata
Example:
Field 2 is a 512 bit value (CHAR64). Field 2 must be specified at offset 0 of a slot. The schema reports slot 1, offset 0. This should be interpreted as using all of slot 1 and slot 2, as slot 2 is the contiguous span.
Field Packing
All fields are packed into an array of uint256 primitive values. uint256s are chosen over bytes because they can be explicitly and directly accessed without having to read any additional storage. Because of the explicit EVM storage slot alignment, optimized reads and writes are possible by grouping fields together into commonly read/updated slots. This allows for a single SLOAD, an in-memory update and a single SSTORE for a number of values in a single slot.
Fields are packed by shifting the value left by the offset of bits.
Example:
Field 1-4 are all UINT64, starting at offsets 0, 64, 128 and 192 respectively. The storage slot would look like:
4444444444444444333333333333333322222222222222221111111111111111
The expression to pack this would be:
The exppression to unpack the fields from this slot would be: