ERC-FIX

FIX Descriptor Specification

Canonicalization, CBOR, and Merkle Specification for Onchain FIX Asset Descriptors

Version 1.0 · Last Updated: September 2025
🎮 First time reading this spec?

Try the interactive explorer to see each step of the transformation process in action. Visualize how FIX messages become canonical trees, CBOR bytes, and Merkle commitments.

Launch Interactive Explorer →

1. Overview#

1.1 Problem Statement#

When tokenizing securities, traditional financial systems need standardized instrument data. The Financial Information eXchange (FIX) Protocol is the de facto standard for describing financial instruments in traditional markets. However, today every blockchain integration requires custom adapters and manual data mapping between token contracts and existing financial infrastructure.

1.2 Solution#

This specification defines how to embed FIX descriptors directly in token contracts using canonical CBOR encoding and Merkle commitments. This enables automatic integration with existing financial infrastructure while maintaining onchain verifiability—without requiring any onchain FIX parsing.

1.3 What This Spec Covers#

  • Converting FIX messages to canonical trees
  • CBOR encoding rules for deterministic representation
  • Merkle commitment generation for efficient field verification
  • Onchain storage patterns (SSTORE2-based)
  • Verification mechanisms for proving specific fields

1.4 What This Spec Does NOT Cover#

  • Which FIX fields to include (business policy decision)
  • Token standards (ERC20, ERC721, etc.)
  • Trading or settlement logic
  • Onchain FIX parsing (all parsing happens off-chain)

1.5 How It Works (High Level)#

Input

A FIX message (or subset) describing a financial instrument—the "asset descriptor"—using standard FIX tags and groups. Example: Symbol, SecurityID, MaturityDate, CouponRate, Parties, etc.

Processing (Off-Chain)
  • Build a canonical tree (deterministic structure with sorted keys)
  • Encode to canonical CBOR (single, unique byte representation)
  • Generate Merkle root committing to every field
Output (Onchain)
  • Minimal descriptor struct in the token contract
  • CBOR bytes stored via SSTORE2 (gas-efficient)
  • Verification function: anyone can prove any field with a Merkle proof

2. Running Example: US Treasury Bond#

Throughout this specification, we'll reference this concrete example: a US Treasury Bond maturing on November 15, 2030, with a 4.25% coupon rate.

FIX Message Input#

55=USTB-2030-11-15        (Symbol)
48=US91282CEZ76           (SecurityID)
22=4                      (SecurityIDSource: ISIN)
167=TBOND                 (SecurityType)
461=DBFTFR                (CFICode)
541=20301115              (MaturityDate)
223=4.250                 (CouponRate)
15=USD                    (Currency)

454=[                     (SecurityAltID group - 2 entries)
  {455=91282CEZ7, 456=1},
  {455=US91282CEZ76, 456=4}
]

453=[                     (Parties group - 2 entries)
  {448=US_TREASURY, 447=D, 452=1},
  {448=CUSTODIAN_BANK_ABC, 447=D, 452=24}
]

Canonical Tree (JSON Representation)#

After parsing and canonicalization (sorting keys, removing session fields):

{
  15: "USD",
  22: "4",
  48: "US91282CEZ76",
  55: "USTB-2030-11-15",
  167: "TBOND",
  223: "4.250",
  453: [
    { 447: "D", 448: "US_TREASURY", 452: "1" },
    { 447: "D", 448: "CUSTODIAN_BANK_ABC", 452: "24" }
  ],
  454: [
    { 455: "91282CEZ7", 456: "1" },
    { 455: "US91282CEZ76", 456: "4" }
  ],
  461: "DBFTFR",
  541: "20301115"
}

CBOR Encoding#

This tree is encoded to canonical CBOR (deterministic binary format):

Size: ~243 bytes
Format: CBOR map with integer keys (sorted), text string values

Merkle Tree#

Each field becomes a Merkle leaf. Example paths:

[15] → "USD" = keccak256(CBOR.encode([15]) || "USD")
[223] → "4.250" = keccak256(CBOR.encode([223]) || "4.250")
[453, 0, 448] → "US_TREASURY" = keccak256(CBOR.encode([453, 0, 448]) || "US_TREASURY")
[454, 1, 456] → "4" = keccak256(CBOR.encode([454, 1, 456]) || "4")

All leaves are sorted and combined into a binary Merkle tree, producing a fixRoot.

Onchain Storage#

FixDescriptor {
  fixMajor: 4,
  fixMinor: 4,
  dictHash: 0x...,
  fixRoot: 0x7a3f... (Merkle root),
  fixCBORPtr: 0x123... (SSTORE2 address),
  fixCBORLen: 243
}
💡 See this in the explorer

Visit the Interactive Explorer to see this exact transformation step-by-step with visualizations of the tree, CBOR bytes, and Merkle structure.

3. Terminology and Notation#

Descriptor
The FIX message subset describing instrument characteristics (not transport/session data). Contains only business-relevant fields like Symbol, SecurityID, MaturityDate, CouponRate, Parties, etc.
Canonical Form
A single, deterministic representation ensuring all implementations produce identical output. Achieved through: sorted map keys, consistent encoding, and removal of optional formatting.
FIX Tag
An integer field identifier defined by the FIX Protocol (e.g., 55=Symbol, 15=Currency, 541=MaturityDate)
Group
A repeating structure in FIX introduced by a "NoXXX" count tag (e.g., 454=NoSecurityAltID, 453=NoPartyIDs). Each group contains N entries where each entry is a map of fields.
Path
The location of a field in the tree, encoded as an array of integers. Scalar fields use [tag]; group fields include the group tag, zero-based entry index, and field tag (e.g., [453, 0, 448] = first Party's PartyID)
Leaf
A (path, value) pair in the Merkle tree representing a single field. Computed as: leaf = keccak256(pathCBOR || valueBytes)
CBOR
Concise Binary Object Representation (RFC 8949) - a binary data format. This spec uses canonical CBOR: definite lengths, sorted map keys, no semantic tags.
SSTORE2
A gas-efficient pattern for storing data in contract bytecode rather than storage slots. Data is deployed as the runtime bytecode of a minimal contract and retrieved via EXTCODECOPY.
Merkle Proof
A list of sibling hashes proving a specific field exists in the committed descriptor. Allows efficient verification of any field without revealing the entire descriptor.
fixRoot
The Merkle root hash committing to all fields in the descriptor. Stored onchain and used to verify field proofs.
Note: Normative keywords MUST, SHOULD, MAY are used per RFC 2119.

4. Architecture Overview#

Before diving into the detailed specifications, here's the big picture of how FIX descriptors flow from input to onchain storage:

FIX Message Input
Standard securities data (business fields)
Canonical Tree
Sort keys, remove session fields, preserve groups
CBOR Encoding
Deterministic binary format
Merkle Tree
Cryptographic commitment
Onchain Storage
FixDescriptor struct
CBOR via SSTORE2
Merkle root
Verification function
Offchain Retrieval
Read CBOR, decode tree
Onchain Verification
Prove fields with Merkle proofs

Key Components#

1. FIX Message → Canonical Tree
Parse FIX, extract business fields, build a hierarchical structure with integer keys and sorted maps.
2. Canonical Tree → CBOR
Serialize to canonical CBOR - a compact binary format that ensures any two implementations produce identical bytes for the same input.
3. Canonical Tree → Merkle Root
Enumerate all fields as (path, value) pairs, hash each to create leaves, sort, and build a binary Merkle tree.
4. Storage → Onchain
Deploy CBOR via SSTORE2, store Merkle root and metadata in a FixDescriptor struct embedded in the token contract.
5. Verification
Anyone can verify any field by providing: path, value, and Merkle proof. Contract hashes the leaf and walks the proof tree to confirm it reaches the stored root.

Why This Design?#

  • Canonical: Multiple implementations produce identical output
  • Compact: CBOR is significantly smaller than JSON or FIX tag=value
  • Verifiable: Merkle proofs allow checking any field without downloading full descriptor
  • Gas-efficient: SSTORE2 reduces storage costs vs traditional storage slots
  • No onchain parsing: All complexity happens off-chain; onchain code only verifies hashes
💡 Visualize this pipeline

The Interactive Explorer lets you step through this exact pipeline with a real Treasury bond example.

5. Descriptor Content#

5.1 Included Fields#

Business and instrument fields such as:

  • Identification: 48 (SecurityID), 22 (SecurityIDSource), 55 (Symbol), 454 (SecurityAltID group)
  • Classification: 167 (SecurityType), 461 (CFICode)
  • Economics/Terms: 15 (Currency), 541 (MaturityDate), 223 (CouponRate)
  • Roles: 453 (Parties group) and nested PartySubIDs if used

5.2 Excluded Fields#

Transport/session mechanics (e.g., 8 (BeginString), 9 (BodyLength), 10 (CheckSum), sequence numbers, admin/session fields) MUST NOT be part of the committed descriptor.

5.3 Dictionary Binding#

Implementations MUST record the FIX version and dictionary used to ensure semantic consistency across implementations:

fixMajor, fixMinor (e.g., 4, 4)
dictHash = keccak256 of the exact FIX dictionary / FIX Orchestra bytes

Example: FIX 4.4 using FIX Trading Community dictionary would have fixMajor=4, fixMinor=4, and dictHash computed from the canonical FIX dictionary file.

6. Canonical Tree Model#

The descriptor is represented as a hierarchical tree. First, let's see an example transformation, then we'll define the rules.

Example Transformation#

Input FIX (simplified):

55=USTB-2030-11-15
167=TBOND
223=4.250
453=[{448=US_TREASURY,452=1}]

Canonical Tree (JSON representation):

{
  55: "USTB-2030-11-15",
  167: "TBOND",
  223: "4.250",
  453: [
    {
      448: "US_TREASURY",
      452: "1"
    }
  ]
}

Note: Keys are integers, values are strings, arrays preserve order, and map keys are sorted.

Structure Rules#

The descriptor is represented as a hierarchical tree:

Scalars
tag → value

Value is the exact FIX value bytes interpreted as UTF-8 text

Groups
groupTag → [ entry0, entry1, … ]

Each entry is a map { tag → value | nested group }

Mandatory Rules#

  1. Each map key is the integer FIX tag
  2. Scalar values are text strings; do not convert numerics—preserve FIX string forms (e.g., "4.250", "20301115")
  3. Group entries:
    • MUST begin with the delimiter field (for human clarity), but map keys are still sorted
    • Optional fields MAY be omitted; absence means "no leaf"
    • Array order is preserved as given by the issuer (indices 0..N-1)

7. Canonical CBOR Encoding#

The canonical tree is serialized to CBOR using canonical form:

Top Level
CBOR map ({}), keys = unsigned integers (FIX tags), sorted ascending
Scalar Value
CBOR text string with exact FIX value bytes (UTF-8). No reformatting
Group
CBOR array ([]) of CBOR maps. Each entry is a map with integer keys sorted ascending
Lengths
Definite lengths only; no indefinite-length items
Tags
No semantic tags are used

Result: This ensures a single, unique CBOR byte string for a given descriptor tree.

8. Merkle Commitment#

8.1 Path Encoding#

Each leaf commits to a (path, valueBytes) pair. Let's start with examples:

[15] → Simple field 15 (Currency)
[223] → Simple field 223 (CouponRate)
[453, 0, 448] → Group 453, first entry, field 448
[454, 1, 456] → Group 454, second entry, field 456
[453, 0, 802, 2, 523] → Nested group example

Path encoding rules: Each path is an array of unsigned integers, encoded as canonical CBOR. Paths are used for both Merkle leaves and verification.

8.2 Leaf Hash#

leaf = keccak256( pathCBOR || valueBytes )
  • pathCBOR: the canonical CBOR bytes of the path array
  • valueBytes: the exact FIX value bytes (UTF-8 string payload, no CBOR framing)

8.3 Leaf Set#

Produce one leaf per present field:

  • Scalars: one leaf for each (tag, value)
  • Each group entry: one leaf per present field inside that entry (with its path including the group index)

8.4 Root Construction#

  1. Sort all leaves by pathCBOR lexicographically (byte order)
  2. Build a standard binary Merkle tree:
    • Pair adjacent leaves; each parent = keccak256(left || right)
    • If odd node remains at a level, promote it (no duplicate hashing)
  3. The final parent is the Merkle root (fixRoot)

8.5 Proofs#

A Merkle proof is the usual vector of sibling hashes from the leaf to the root. The verifier needs:

pathCBOR (bytes)
valueBytes (bytes)
siblingHashes[]: bytes32[]
directions[]: bool[]
fixRoot: bytes32

9. Onchain Representation#

9.1 Integration with Asset Contracts#

The FixDescriptor MUST be embedded directly in the asset contract (ERC20, ERC721, etc.) rather than stored in a separate registry. This eliminates permissioning issues, creates an implicit mapping from asset address to descriptor, and ensures the issuer retains full control.

9.2 Descriptor Struct#

struct FixDescriptor {
  uint16  fixMajor;           // e.g., 4
  uint16  fixMinor;           // e.g., 4
  bytes32 dictHash;           // FIX dictionary hash
  address dictionaryContract; // FixDictionary for tag lookups
  bytes32 fixRoot;            // Merkle root
  address fixCBORPtr;         // SSTORE2 data address
  uint32  fixCBORLen;         // CBOR length
  string  fixURI;             // optional mirror
}

9.3 Standard Interface#

interface IFixDescriptor {
  function getFixDescriptor() external view returns (FixDescriptor memory descriptor);
  function getFixRoot() external view returns (bytes32 root);
  function verifyField(
    bytes calldata pathCBOR,
    bytes calldata value,
    bytes32[] calldata proof,
    bool[] calldata directions
  ) external view returns (bool valid);
  function getHumanReadableDescriptor() external view returns (string memory);
}

9.4 CBOR Storage (SSTORE2 Pattern)#

  • The CBOR is deployed as the runtime bytecode of a minimal data contract (prefixed with a STOP byte)
  • Anyone can retrieve bytes via eth_getCode(fixCBORPtr)
  • Optionally expose a chunk retrieval function using EXTCODECOPY

9.5 Events and Versioning#

event FixDescriptorSet(bytes32 fixRoot, bytes32 dictHash, address fixCBORPtr, uint32 fixCBORLen)
event FixDescriptorUpdated(bytes32 oldRoot, bytes32 newRoot, address newPtr)

10. Human-Readable Output#

While the canonical CBOR encoding provides compact and deterministic storage, it uses numeric tag values that are not human-readable. The getHumanReadableDescriptor() function provides an on-chain method to generate a human-readable representation of the FIX descriptor by substituting tag numbers with their textual names from a FIX dictionary.

10.1 The getHumanReadableDescriptor() Function#

function getHumanReadableDescriptor() external view returns (string memory)

This function:

  • Reads the CBOR-encoded descriptor from the SSTORE2 contract
  • Parses the CBOR map to extract tags and values
  • Looks up human-readable tag names from the FixDictionary contract
  • Formats the output in FIX format: TagName=Value|TagName2=Value2|...
  • Handles both scalar fields and repeating groups

10.2 Output Format#

Scalar Fields:
Symbol=AAPL|SecurityID=US0378331005|SecurityIDSource=1|SecurityType=CS|Currency=USD
Repeating Groups:
NoSecurityAltID=2|[0]SecurityAltID=000402AJ1|[0]SecurityAltIDSource=1|[1]SecurityAltID=US000402AJ19|[1]SecurityAltIDSource=4

10.3 Benefits#

  • On-chain Composability: Other contracts can call this function to read human-readable descriptors
  • No Off-chain Dependencies: Everything is verifiable and readable directly on the blockchain
  • Gas Efficient: Uses optimized SSTORE2 pattern for dictionary storage
  • Standard Compliance: Output follows FIX protocol format conventions

10.4 On-chain vs Off-chain Decoding#

Both approaches can show human-readable tag names. The key difference is WHERE decoding happens and WHETHER other contracts can call it.

Off-chain Decoding
  • Uses fixparser library (JavaScript/TypeScript)
  • Can show tag names from off-chain dictionaries
  • 0 gas cost (view call)
  • Not callable by other smart contracts
  • Requires off-chain infrastructure/libraries
On-chain Human-Readable
  • Calls getHumanReadableDescriptor() on the contract
  • Shows tag names from on-chain FixDictionary
  • 0 gas cost (when called as view)
  • ~200k-500k gas (when called by another contract)
  • Fully composable with other smart contracts
  • Trustless, no off-chain dependencies

11. FIX Dictionary Architecture#

The FIX Dictionary provides an on-chain mapping from numeric FIX tag numbers to their human-readable names. It uses an innovative storage strategy that eliminates expensive mapping lookups by storing tag names in fixed-size slots, enabling O(1) direct indexing.

11.1 Storage Strategy#

Instead of using a Solidity mapping, the dictionary stores all tag names in a single SSTORE2 contract with a fixed 24-byte slot per tag:

Slot Structure (24 bytes per tag):
Byte 0: Length of tag name (0-23)
Bytes 1-23: UTF-8 encoded tag name (zero-padded)

Example for Tag 15 (Currency):

Offset: 15 × 24 = 360 bytes
[Slot at offset 360]
Byte 0: 0x08 (length = 8)
Bytes 1-8: "Currency"
Bytes 9-23: 0x00... (zero padding)

11.2 Tag Name Lookup#

function getTagName(uint16 tag) public view returns (string memory)
offset = tag × 24 + 1
extcodecopy(dataContract, slot, offset, 24)

11.3 Gas Efficiency#

  • No Expensive Mappings: Avoids 20,000+ gas per SSTORE for mapping updates
  • Single Deployment: All 957 tags stored in one SSTORE2 contract (~23KB)
  • O(1) Lookups: Direct offset calculation without iteration
  • EXTCODECOPY: Efficient bytecode reading (100 gas + 3 gas/word)

11.4 Dictionary Versioning#

Different FIX versions (4.2, 4.4, 5.0) can have different dictionaries. The FixDictionaryFactory contract manages deployments keyed by FIX major and minor version numbers.

mapping(uint16 => mapping(uint16 => FixDictionary)) public dictionaries;

12. Onchain Verification#

Library Interface#

library FixMerkleVerifier {
  function verify(
      bytes32 root,
      bytes calldata pathCBOR,
      bytes calldata value,
      bytes32[] calldata proof,
      bool[] calldata directions
  ) internal pure returns (bool);
}

Verification Algorithm#

  1. bytes32 leaf = keccak256(abi.encodePacked(pathCBOR, value))
  2. For each sibling in proof with corresponding direction in directions: if current node is right, parent = keccak256(sibling || current); if left, parent = keccak256(current || sibling)
  3. Compare final parent to root

13. Offchain Retrieval#

Once a FIX descriptor is committed onchain, participants MUST be able to retrieve the canonical CBOR representation and reconstruct the original descriptor tree. This section specifies the retrieval interface and decoding requirements.

11.1 Retrieval Interface#

Token contracts that store FIX descriptors SHOULD expose a function to retrieve the CBOR-encoded canonical tree. The retrieval function MUST support chunked access to accommodate large descriptors.

function getFixCBORChunk(uint256 start, uint256 size)
    external view returns (bytes memory);
  • Chunked Access: The function accepts start offset and size parameters, allowing callers to retrieve large CBOR in multiple transactions to manage gas costs.
  • Bounds Handling: Implementations MUST clamp the requested range to available data and return an empty bytes array if the start offset exceeds the CBOR length.
  • SSTORE2 Access: Since CBOR is stored via SSTORE2 (as contract bytecode), retrieval functions SHOULD use efficient bytecode access patterns to minimize gas consumption.

11.2 CBOR Decoding Requirements#

Retrieved CBOR bytes MUST be decoded according to the canonical structure defined in Section 6. Decoders MUST reconstruct the descriptor tree with the following guarantees:

  • CBOR maps SHALL be converted to descriptor tree objects with numeric tag keys
  • Scalar string values SHALL remain as UTF-8 text
  • CBOR arrays SHALL be decoded as group entries, each containing a map of fields
  • Decoders MUST preserve the canonical key ordering present in the CBOR encoding

11.3 FIX Message Reconstruction#

After decoding CBOR to the descriptor tree, applications MAY reconstruct a FIX message representation. The reconstruction process SHALL:

  1. Traverse the descriptor tree in numeric tag order (canonically sorted)
  2. Emit scalar fields as tag=value pairs
  3. For group nodes, emit the group count tag followed by entry fields in sequence
  4. Optionally add FIX session headers (BeginString, BodyLength, MsgType) and trailer (CheckSum) for display purposes

Note on Session Fields

Session fields (tags 8, 9, 10, 34, 35, 49, 52, 56) are excluded from the canonical tree and CBOR encoding. Reconstructed messages MAY include synthetic session headers for compatibility with FIX parsers, but these MUST NOT affect the Merkle root or verification.

11.4 Use Cases#

Onchain retrieval enables several important workflows:

  • Transparency: Any party can audit the complete descriptor data associated with a tokenized asset without relying on off-chain sources
  • Interoperability: Third-party contracts can read descriptor fields to make decisions (e.g., risk assessment based on maturity date)
  • Verification: Off-chain systems can retrieve CBOR, enumerate leaves, and generate Merkle proofs for specific fields to be verified onchain
  • Compliance: Regulators or auditors can independently verify that onchain descriptors match disclosed security information

14. Security Considerations#

Trust Assumptions#

  • Issuer Control: The descriptor is set by the token contract issuer. There is no external authority validating the FIX data accuracy—users must trust the issuer.
  • Immutability vs Updates: Contracts can be designed with fixed descriptors (immutable) or updatable descriptors (governed by issuer). Both patterns are valid; the choice is a business decision.
  • Dictionary Hash: The dictHash ensures all parties use the same FIX dictionary. Mismatched dictionaries can lead to semantic disagreements about field meanings.

What Merkle Proofs Guarantee#

✓ Merkle proofs prove:

  • A specific field at a specific path has a specific value
  • The field is part of the canonical tree committed to
  • No one can present a false value without breaking the proof

✗ Merkle proofs do NOT prove:

  • The accuracy of the descriptor data
  • The completeness of the descriptor
  • Real-world correspondence (e.g., ISIN validity)

15. Gas Cost Analysis#

Understanding gas costs helps implementers make informed decisions about descriptor size and verification strategies.

15.1 Human-Readable Descriptor Costs#

The human-readable descriptor feature introduces additional gas considerations for deployment and usage.

One-Time Deployment Costs
FixDictionary (23KB): ~8,700,000 gas
FixDictionaryFactory: ~620,000 gas
Cost on L1 (30 gwei): ~$650 USD
Cost on L2 (0.001 gwei): ~$0.02 USD
Off-chain Usage (View Calls)
0 gasGas Cost
View functions execute locally without transactions. Unlimited free calls for web apps, analytics, and data explorers.
On-chain Usage (Contract Calls)
lowSimple descriptor (5 fields): ~180,000 gas
mediumMedium descriptor (12 fields): ~250,000 gas
highComplex descriptor (25+ fields): ~500,000 gas
Per-tag lookup cost: ~4,400 gas (O(1) constant time)

15.2 Base Operation Costs#

Deployment Costs#

CBOR Storage (SSTORE2)
  • ~200 gas per byte + ~32k deployment overhead
  • Example: 243-byte descriptor ≈ 80k gas
  • 3-4x cheaper than traditional storage slots
Descriptor Struct Storage + Verification
  • FixDescriptor struct: ~60-80k gas (3-4 slots)
  • Total deployment: ~140-160k gas (typical)
  • verifyField() call: ~30-40k gas (depth 4-6)

16. Implementation Guide#

Given a FIX descriptor message, follow this implementation flow:

1
Parse FIX
Extract only business fields (exclude session tags - see Section 5)
2
Build Canonical Tree
Map scalars directly; create array of entry maps for groups (see Section 6)
3
Serialize to CBOR
Use canonical form - integer keys sorted, definite lengths (see Section 7)
4
Enumerate Leaves
Compute pathCBOR for each present field; collect (pathCBOR, valueBytes) pairs (see Section 8.1-8.3)
5
Compute Merkle Root
Sort leaves by pathCBOR; build binary Merkle tree using keccak256 (see Section 8.4)
6
Deploy CBOR
Deploy as SSTORE2-style data contract; return fixCBORPtr and fixCBORLen (see Section 9.4)
7
Set Descriptor
Store in the asset contract (not a registry): fixMajor, fixMinor, dictHash, fixRoot, fixCBORPtr, fixCBORLen, fixURI (see Section 9.2)
8
Emit Event
Emit FixDescriptorSet event for indexing (see Section 9.5)
9
Produce Utilities
Build proof generator and reader tools for fetching CBOR and generating proofs off-chain
💡 Reference Implementation

This specification has a complete reference implementation available in two forms:

Interactive Explorer:
Try the web interface to see the transformation pipeline in action with live visualizations.
Open Source Code:
View the complete source code on GitHub, including:
  • TypeScript library (packages/fixdescriptorkit-typescript)
  • Solidity smart contracts (contracts/src)
  • Web application (apps/web)
  • Test suites and examples

FixDescriptorKit Specification v1.0

Try the ExplorerView on GitHub