# ExchangeRates¶

## Description¶

This contract stores the latest Synth exchange rates. These rates are set by an oracle, which updates this contract every three minutes with any prices that have moved sufficiently. Once set, these prices are available for any contract in the Synthetix system to query. Prices which have not been updated recently enough are considered stale; Synthetix functionality using stale prices does not operate. All rates are denominated in terms of sUSD, so the price of sUSD is always \$1.00, and is never stale.

The ExchangeRates contract is also responsible for computing the prices of various derived synths. In particular, the behaviour of inverse synths is defined here. These are derivative synths whose price varies inversely with the price of an underlying asset.

This contract interacts with the oracle's frontrunning protection, which is partially described in SIP-6 and SIP-7.

This does not turn off any functionality in the exchange rate contract, but is used by Synthetix to disable currency exchanges while prices are being updated to protect against oracle front running. The lock is released when rate updates have completed.

Source: contracts/ExchangeRates.sol

## Architecture¶

### Inheritance Graph¶

graph TD ExchangeRates[ExchangeRates] --> SelfDestructible[SelfDestructible] SelfDestructible[SelfDestructible] --> Owned[Owned]

Details
• oracle: This address is not actually a contract, but it is the source of prices for this contract.
• Aggregators: These are a collection of decentralized pricing networks that collect and aggregate results from a network of oracles.
• PurgeableSynth: exchange rates are used to determine if the total token value is below the purge threshold.
• Synthetix: the value of tokens is used to in order to facilitate exchange between them, and to ensure exchanges cannot occur while price updates and being made or if a particular exchange rate is stale.

## Structs¶

### InversePricing¶

Source

Holds necessary information for computing the price of inverse Synths.

Field Type Description
entryPoint uint256 The underlying asset's price at the time the inverse index was set up. Must be strictly greater than $0$.
upperLimit uint256 The upper limit of the inverse price. Must lie strictly between entryPoint and twice entryPoint.
lowerLimit uint256 The lower limit of the inverse price. Must lie strictly between $0$ and entryPoint.
frozen bool True if an inverse Synth has breached one of its limits.

### RateAndUpdatedTime¶

Source

Field Type Description
rate uint216 The rate of the currency (with 18 decimals)
time uint40 The timestamp (in secs) of the block when the rate was persisted

## Variables¶

### aggregatorKeys¶

Source

A list of the keys of currencies with a decentralized aggregated pricing network.

Type: bytes32[]

### aggregators¶

Source

For each currency with a decentralized aggregated pricing network, return the Aggregation contract address.

Type: mapping(bytes32 => contract AggregatorInterface)

### currentRoundForRate¶

Source

Type: mapping(bytes32 => uint256)

### inversePricing¶

Source

For each currency with an inverse index, keep the necessary InversePricing information to maintain the index.

Type: mapping(bytes32 => struct ExchangeRates.InversePricing)

### invertedKeys¶

Source

A list of the keys of currencies with an inverted index.

Type: bytes32[]

### oracle¶

Source

The address which is permitted to push rate updates to the contract.

Type: address

### rateStalePeriod¶

Source

The duration after which a rate will be considered out of date. Synth exchange and other price-sensitive transactions in the Synthetix contract will not operate if a relevant rate is stale. Initialised to $3$ hours.

Type: uint256

## Constructor¶

### constructor¶

Source

Initialises the oracle address and initial currency prices, along with the inherited SelfDestructible instance.

Details

Signature

(address _owner, address _oracle, bytes32[] _currencyKeys, uint256[] _newRates)

Visibility

public

State Mutability

nonpayable

Requires

## Views¶

### anyRateIsStale¶

Source

Loop over the given array of currencies and return true if any of them is stale. sUSD's rate is never stale. Rates for nonexistent currencies are always stale.

Details

Signature

anyRateIsStale(bytes32[] currencyKeys) returns (bool)

Visibility

external

State Mutability

view

### effectiveValue¶

Source

Given a quantity of a source currency, returns a quantity of a destination currency that is of equivalent value at current exchange rates, if those rates are fresh.

The effective value is computed as a simple ratio of the prices of the currencies concerned. That is, to convert a quantity $Q_A$ of currency $A$ to currency $B$ at prices $\pi_A$ and $\pi_B$, the quantity $Q_B$ received is:

Q_B = Q_A \frac{\pi_A}{\pi_B}

This computation is simple because all fractional quantities in the Synthetix system except for the debt ledger are 18 decimal fixed point numbers.

Details

Signature

effectiveValue(bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey) returns (uint256)

Visibility

external

State Mutability

view

### effectiveValueAndRates¶

Source

Details

Signature

effectiveValueAndRates(bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey) returns (uint256, uint256, uint256)

Visibility

external

State Mutability

view

### effectiveValueAtRound¶

Source

Details

Signature

effectiveValueAtRound(bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey, uint256 roundIdForSrc, uint256 roundIdForDest) returns (uint256)

Visibility

external

State Mutability

view

### getCurrentRoundId¶

Source

Details

Signature

getCurrentRoundId(bytes32 currencyKey) returns (uint256)

Visibility

external

State Mutability

view

### getLastRoundIdBeforeElapsedSecs¶

Source

Details

Signature

getLastRoundIdBeforeElapsedSecs(bytes32 currencyKey, uint256 startingRoundId, uint256 startingTimestamp, uint256 timediff) returns (uint256)

Visibility

external

State Mutability

view

### lastRateUpdateTimes¶

Source

Retrieves the timestamp the given rate was last updated. Accessed by the same keys as rates is.

Details

Signature

lastRateUpdateTimes(bytes32 currencyKey) returns (uint256)

Visibility

external

State Mutability

view

### lastRateUpdateTimesForCurrencies¶

Source

Maps lastRateUpdateTimes over an array of keys.

Details

Signature

lastRateUpdateTimesForCurrencies(bytes32[] currencyKeys) returns (uint256[])

Visibility

external

State Mutability

view

### rateAndTimestampAtRound¶

Source

Details

Signature

rateAndTimestampAtRound(bytes32 currencyKey, uint256 roundId) returns (uint256, uint256)

Visibility

external

State Mutability

view

### rateAndUpdatedTime¶

Source

Details

Signature

rateAndUpdatedTime(bytes32 currencyKey) returns (uint256, uint256)

Visibility

external

State Mutability

view

### rateForCurrency¶

Source

Returns the last recorded rate for the given currency. This is just an alias to the public mapping rates, so it could probably be eliminated.

Details

Signature

rateForCurrency(bytes32 currencyKey) returns (uint256)

Visibility

external

State Mutability

view

### rateIsFrozen¶

Source

Returns true if the inverse price for the given currency is frozen. This is simply an alias to inversePricing[currencyKey].frozen. Currencies without an inverse price will naturally return false.

Details

Signature

rateIsFrozen(bytes32 currencyKey) returns (bool)

Visibility

external

State Mutability

view

### rateIsStale¶

Source

The rate for a given currency is stale if its last update occurred more than rateStalePeriod seconds ago.

sUSD is a special case; since its rate is fixed at $1.0$, it is never stale. The rates of nonexistent currencies are always stale.

Details

Signature

rateIsStale(bytes32 currencyKey) returns (bool)

Visibility

external

State Mutability

view

### ratesAndStaleForCurrencies¶

Source

Details

Signature

ratesAndStaleForCurrencies(bytes32[] currencyKeys) returns (uint256[], bool)

Visibility

external

State Mutability

view

### ratesAndUpdatedTimeForCurrencyLastNRounds¶

Source

Details

Signature

ratesAndUpdatedTimeForCurrencyLastNRounds(bytes32 currencyKey, uint256 numRounds) returns (uint256[], uint256[])

Visibility

external

State Mutability

view

### ratesForCurrencies¶

Source

Maps rateForCurrency over an array of keys.

Details

Signature

ratesForCurrencies(bytes32[] currencyKeys) returns (uint256[])

Visibility

external

State Mutability

view

## Restricted Functions¶

### addAggregator¶

Source

Details

Signature

addAggregator(bytes32 currencyKey, address aggregatorAddress)

Visibility

external

State Mutability

nonpayable

Requires

Modifiers

Emits

### deleteRate¶

Source

Deletes a currency's price and its update time from the ExchangeRates contract.

Details

Signature

deleteRate(bytes32 currencyKey)

Visibility

external

State Mutability

nonpayable

Requires

Modifiers

Emits

### removeAggregator¶

Source

Details

Signature

removeAggregator(bytes32 currencyKey)

Visibility

external

State Mutability

nonpayable

Requires

Modifiers

### removeInversePricing¶

Source

Allows the owner to remove an inverse index for a particular currency.

Details

Signature

removeInversePricing(bytes32 currencyKey)

Visibility

external

State Mutability

nonpayable

Requires

Modifiers

### setInversePricing¶

Source

Allows the owner to set up an inverse index for a particular currency. See rateOrInverted for computation details. New inverse indexes begin unfrozen.

Details

Signature

setInversePricing(bytes32 currencyKey, uint256 entryPoint, uint256 upperLimit, uint256 lowerLimit, bool freeze, bool freezeAtUpperLimit)

Visibility

external

State Mutability

nonpayable

Requires

Modifiers

Emits

### setOracle¶

Source

Allows the owner to set the address which is permitted to send prices to this contract.

Details

Signature

setOracle(address _oracle)

Visibility

external

State Mutability

nonpayable

Modifiers

Emits

### setRateStalePeriod¶

Source

Allows the owner to set the time after which rates will be considered stale.

Details

Signature

setRateStalePeriod(uint256 _time)

Visibility

external

State Mutability

nonpayable

Modifiers

Emits

### updateRates¶

Source

Allows the oracle to update exchange rates in the contract. Otherwise this is just an alias to internalUpdateRates.

Details

Signature

updateRates(bytes32[] currencyKeys, uint256[] newRates, uint256 timeSent) returns (bool)

Visibility

external

State Mutability

nonpayable

Modifiers

## Internal Functions¶

### _effectiveValueAndRates¶

Source

Details

Signature

_effectiveValueAndRates(bytes32 sourceCurrencyKey, uint256 sourceAmount, bytes32 destinationCurrencyKey) returns (uint256, uint256, uint256)

Visibility

internal

State Mutability

view

### _getCurrentRoundId¶

Source

Details

Signature

_getCurrentRoundId(bytes32 currencyKey) returns (uint256)

Visibility

internal

State Mutability

view

### _getRate¶

Source

Details

Signature

_getRate(bytes32 currencyKey) returns (uint256)

Visibility

internal

State Mutability

view

### _getRateAndTimestampAtRound¶

Source

Details

Signature

_getRateAndTimestampAtRound(bytes32 currencyKey, uint256 roundId) returns (uint256, uint256)

Visibility

internal

State Mutability

view

### _getRateAndUpdatedTime¶

Source

Details

Signature

_getRateAndUpdatedTime(bytes32 currencyKey) returns (struct ExchangeRates.RateAndUpdatedTime)

Visibility

internal

State Mutability

view

### _getUpdatedTime¶

Source

Details

Signature

_getUpdatedTime(bytes32 currencyKey) returns (uint256)

Visibility

internal

State Mutability

view

### _setRate¶

Source

Updates the rate and timestamp for the individual rate using an internal struct.

Details

Signature

_setRate(bytes32 currencyKey, uint256 rate, uint256 time)

Visibility

internal

State Mutability

nonpayable

### internalUpdateRates¶

Source

Record the set of provided rates and the timestamp, handling any inverse indexes with rateOrInverted. At this stage inverse indexes which escaped their bounds are frozen. Any rate with a more recent update time is skipped.

Finally, the price update lock is reset, reenabling Synth exchange functionality.

The timeSent argument is useful for maintaining the exact age of the data points even as transactions can take a variable amount of time to confirm. Without this, earlier updates could possibly overwrite later ones.

Returns true if no exception was thrown.

Details

Signature

internalUpdateRates(bytes32[] currencyKeys, uint256[] newRates, uint256 timeSent) returns (bool)

Visibility

internal

State Mutability

nonpayable

Requires

Emits

### rateOrInverted¶

Source

Returns the current price for a specified currency key.

If a currency is not an inverted index, then just return the rate that was passed in. If the currency is an inverted index, return the inverted rate. If the inverted price reaches one of its limits, freeze its rate at the limit it breached. Future calls to a frozen inverted index will return the last recorded rate. That is, frozen rates can no longer be updated.

An inverted rate moves exactly inverse to the underlying price; if the underlying price moves up a dollar, the inverted price moves down a dollar. The price $\bar{p}$ of an inverse index $c$ with base price $p$, entry point $e$, and lower and upper limits $l$ and $u$ respectively, is computed as:

\bar{p} = \text{clamp(}2e - p, \ l, \ u\text{)}

With $0 \lt l \lt e \lt u \lt 2e$ enforced by setInversePricing.1

So if $p$ moves from $e$ to $e + \delta$, then $\bar{p}$ moves to $e - \delta$, if it would not be frozen. $\bar{p}$ is frozen whenever $\bar{p} \in \{l,u\}$; that is, when $2e - l \le p$ or $p \le 2e - u$. This implies that $p$ can never exceed twice its entry point without $\bar{p}$ being frozen, but in principle it could reach almost to zero.

Details

Signature

rateOrInverted(bytes32 currencyKey, uint256 rate) returns (uint256)

Visibility

internal

State Mutability

nonpayable

### removeFromArray¶

Source

Helper function that removes an entry from an existing array in storage. Returns true if found and removed, false otherwise.

Details

Signature

removeFromArray(bytes32 entry, bytes32[] array) returns (bool)

Visibility

internal

State Mutability

nonpayable

## Modifiers¶

### onlyOracle¶

Source

Reverts the transaction if msg.sender is not the oracle.

## Events¶

### AggregatorAdded¶

Source

Records that an Aggregator pricing network was added

Signature: AggregatorAdded(bytes32 currencyKey, address aggregator)

### AggregatorRemoved¶

Source

Records that an Aggregator pricing network was removed

Signature: AggregatorRemoved(bytes32 currencyKey, address aggregator)

### InversePriceConfigured¶

Source

Records that an inverse price index was set up or deleted. As there is no distinct event for deletion, this is signaled by providing zero values to all arguments barring currencyKey.

Signature: InversePriceConfigured(bytes32 currencyKey, uint256 entryPoint, uint256 upperLimit, uint256 lowerLimit)

### InversePriceFrozen¶

Source

Records that an inverse price breached a limit and was frozen.

Signature: InversePriceFrozen(bytes32 currencyKey)

### OracleUpdated¶

Source

Records that the anointed oracle was updated.

Signature: OracleUpdated(address newOracle)

### RateDeleted¶

Source

Signature: RateDeleted(bytes32 currencyKey)

### RateStalePeriodUpdated¶

Source

Records that the stale period was altered.

Signature: RateStalePeriodUpdated(uint256 rateStalePeriod)

### RatesUpdated¶

Source

Records that a set of currency prices were updated.

Signature: RatesUpdated(bytes32[] currencyKeys, uint256[] newRates)

1. The clamp function can be defined thus: clamp(v, l, u) = min(max(v, l), u)