Context
Oracles and FX feeds quote against fiat (USD, EUR, ...), which is not a Stellar asset and has no code+issuer. The first oracle code faked it as a classic asset with an empty issuer, which rendered as USD- and broke ParseAsset round-trips.
Decision
canonical.AssetType has a fiat variant, AssetFiat = "fiat"; the sentinel form is removed.
- String form is
fiat:USD, object form is{"type": "fiat", "code": "USD"}, and SQL storage is the same text column as other assets. - A fiat asset carries only
Code;IssuerandContractIDstay empty. Asset.Validateaccepts a fiat code only ifcanonical.IsKnownFiat(code); the allow-list isknownFiatCodesininternal/canonical/asset_fiat.go, currently 133 codes (ISO-4217 plus the massive.com FX feed's set plus VES).- Adding a fiat code is a one-line code change to that list, never a new ADR.
- Commodities such as XAU are not currencies; they belong to the
rwa:namespace (ADR-0028). Crypto tickers usecrypto:(ADR-0014). - Rejected: a synthetic issuer address, a separate
FiatCurrencytype, an empty-issuer classic asset, and a fake contract asset.
Invariant
- A fiat asset has no issuer or contract id and an allow-listed code;
Asset.Validateenforces it. Asset.String()andParseAssetround-trip every asset shape including fiat; theasset_test.goandasset_fiat_test.gotables enforce it.- Every
switchoverAssetTypeeither covers every variant, has adefaultwith a real body (not empty or onlyfallthrough/break), or carries an//exhaustive:ignoremarker with prose;TestAssetTypeExhaustiveGuardininternal/canonical/asset_type_exhaustive_guard_test.goenforces it. - No code accepts an empty-issuer classic asset as fiat.
Consequences
Each new AssetType variant forces every switch that lacks a real default to add a case, which the guard finds. Fiat-quoted API responses are self-describing ("quote": "fiat:USD"), and triangulation can treat the USD anchor as a real value. The pre-v1 sentinel was never shipped, so no data migration was needed.
Evidence
internal/canonical/asset.go, asset_fiat.go, oracle.go, and the exhaustive guard test above. Grammar: docs/reference/api-design.md section 3.