Skip to main content
CurrencyRegistry answers one question for the factory and the router: for currency code X, which token is the quote asset, how many decimals does it have, is it a real stablecoin or a synthetic, where is its vault, and may new launches use it. Changes only affect launches created afterwards; an existing curve keeps its quote asset forever. Source: contracts/src/CurrencyRegistry.sol (Ownable2Step). Interface: contracts/src/interfaces/ICurrencyRegistry.sol. Addresses: Addresses.

Configuration record

The constructor registers "USD" (the constant USD = "USD") as tier 1 with usdc as its quote asset and records the oracle. usdc is immutable; the oracle can be replaced.

Views

Codes are ASCII right-padded to 32 bytes: "INR" is 0x494e520000000000000000000000000000000000000000000000000000000000. In viem: stringToHex("INR", { size: 32 }); with Foundry: cast --format-bytes32-string INR.

Owner functions

setOracle replaces the registry’s oracle (ZeroAddress for 0x0). It changes what the factory uses to size new curves and what the router charges as an update fee. It does not change the oracle of any existing vault: each FxVault stores its oracle as an immutable at creation. See Oracles. setRealCurrency registers, or re-registers, a tier-1 stablecoin for a code. The oracle must support the code (NotSupportedByOracle), the asset must be non-zero and have at most 18 decimals (DecimalsTooHigh). Calling it for a code that already exists overwrites the record: this is how a currency moves from tier 2 to tier 1 when a real stablecoin lands, without touching launches already quoted in the synthetic. The reverse lookup for the new asset is set; the old synthetic keeps its own reverse entry. createSynthetic deploys a SynthToken(name, symbol) and an FxVault for the code, wires them (setVault), registers the pair as tier 2 with 18 decimals and enables it. The vault is owned by the registry’s current owner, uses the registry’s dollar and current oracle, and is named "<name> Underwriter" / "uw-<symbol>" for its share token. Reverts NotSupportedByOracle(code) if the oracle does not list the code and AlreadyExists(code) if the code already has a quote asset. A code can therefore never get a second synthetic. setEnabled toggles whether new launches may use a code (UnknownCurrency for unregistered codes). Disabling a currency stops createLaunch for it; trading, minting and redeeming continue. The owner cannot remove a code, change a synthetic’s vault, or edit a vault’s parameters from here (vault parameters are set on the vault itself; the registry owner is also each vault’s owner at creation).

Events

The indexer seeds its currency table from allCodes() + get(code) and keeps it in sync from CurrencySet (see Currencies query).

Errors

How tiers are decided

Tier is a property of the registration, not of the currency. The deploy script registers USD (always), EUR when the chain has EURC and the script is told about it, and the sixty synthetics from Currencies.sol with the vault parameters in FxVault. Tier 1 with quoteAsset == usdc() is the USD case the router and factory special-case; tier 1 with any other asset (EURC) can only be traded and launched with that asset directly; tier 2 goes through the vault. Any ISO currency that is not registered can still be a display currency in the app, converted off-chain.

Reading the registry