The system design document in our Github repository provides an overview of the smart contracts architecture and details about the protocol implementation. See the developer documentation for technical details on the smart-contract interfaces and functionalities

The Protocol Operations chapter explains how these contracts work together to provide the core functionality of the protocol.

Deployed Contracts

Many Reserve Protocol smart contracts rely on the proxy pattern, whereby users interact with proxy contracts which store data but which do not contain business logic. Rather, all function calls in these proxy contracts are delegated to implementation contracts to execute the desired logic. Implementation contracts for the most recent version of the protocol are provided below.

Mainnet Addresses (v3.0.1)

Implementation Contracts Address
tradingLib 0xB81a1fa9A497953CEC7f370CACFA5cc364871A73
facadeRead 0x81b9Ae0740CcA7cDc5211b2737de735FBC4BeB3C
facadeAct 0x801fF27bacc7C00fBef17FC901504c79D59E845C
facadeWriteLib 0x908Cd3B4B4B6c60d5EB7d1Ca7ECda0e7ceCd6dB1
facadeWrite 0x41edAFFB50CA1c2FEC86C629F845b8490ced8A2c
deployer 0x43587CAA7dE69C3c2aD0fb73D4C9da67A8E35b0b
rsrAsset 0x7edD40933DfdA0ecEe1ad3E61a5044962284e1A6
main 0xF5366f67FF66A3CefcB18809a762D5b5931FebF8
gnosisTrade 0x4e9B97957a0d1F4c25E42Ccc69E4d2665433FEA3
dutchTrade 0x2387C22727ACb91519b80A15AEf393ad40dFdb2F
assetRegistry 0x773cf50adCF1730964D4A9b664BaEd4b9FFC2450
backingManager 0xBbC532A80DD141449330c1232C953Da6801Aed01
basketHandler 0x5ccca36CbB66a4E4033B08b4F6D7bAc96bA55cDc
broker 0x9A5F8A9bB91a868b7501139eEdB20dC129D28F04
distributor 0x0e8439a17bA5cBb2D9823c03a02566B9dd5d96Ac
furnace 0x99580Fc649c02347eBc7750524CAAe5cAcf9d34c
rsrTrader 0x5e3e13d3d2a0adfe16f8EF5E7a2992A88E9e65AF
rTokenTrader 0x5e3e13d3d2a0adfe16f8EF5E7a2992A88E9e65AF
rToken 0xb6f01Aa21defA4a4DE33Bed16BcC06cfd23b6A6F
stRSR 0xC98eaFc9F249D90e3E35E729e3679DD75A899c10

Base Addresses (v3.0.1)

Implementation Contracts Address
tradingLib 0x4E01677488384B851EeAa09C8b8F6Dd0b16d7E9B
facadeRead 0xe1aa15DA8b993c6312BAeD91E0b470AE405F91BF
facadeAct 0x3d6D679c863858E89e35c925F937F5814ca687F3
facadeWriteLib 0x13B63e7094B61CCbe79CAe3fb602DFd12D59314a
facadeWrite 0x46c600CB3Fb7Bf386F8f53952D64aC028e289AFb
deployer 0x9C75314AFD011F22648ca9C655b61674e27bA4AC
rsrAsset 0x23b57479327f9BccE6A1F6Be65F3dAa3C9Db797B
main 0x1D6d0B74E7A701aE5C2E11967b242E9861275143
gnosisTrade 0xcD033976a011F41D2AB6ef47984041568F818E73
dutchTrade 0xDfCc89cf76aC93D113A21Da8fbfA63365b1E3DC7
assetRegistry 0x9c387fc258061bd3E02c851F36aE227DB03a396C
backingManager 0x8569D60Df34354CDd1115b90de832845b31C28d2
basketHandler 0x25E92785C1AC01B397224E0534f3D626868A1Cbf
broker 0x12c3BB1B0da85fDaE0137aE8fDe901F7D0e106ba
distributor 0xd31de64957b79435bfc702044590ac417e02c19B
furnace 0x45D7dFE976cdF80962d863A66918346a457b87Bd
rsrTrader 0xf4C5d33DABb9D4681ED9b83618d629BA1006AE16
rTokenTrader 0xf4C5d33DABb9D4681ED9b83618d629BA1006AE16
rToken 0xA42850A760151bb3ACF17E7f8643EB4d864bF7a6
stRSR 0x53321f03A7cce52413515DFD0527e0163ec69A46

Some Monetary Units

Reserve Protocol refers to units of financial value in a handful of different ways, and treats them as different dimensions. Some of these distinctions may seem like splitting hairs if you're just thinking about one or two example RTokens, but the differences are crucial to understanding how the protocol works in a wide variety of different settings.

The following are the three main financial units that apply to the protocol:

  • Unit of Account: any particular RToken must have a single Unit of Account. This unit is used internally to compare the values of different assets, as when deciding when there's enough revenue to start an auction, or in which of several surplus assets we hold the largest surplus.

    By default, the unit of account for all RTokens is USD. As this financial unit is mostly for internal calculations (such as converting price feeds), there is no reason for an RToken deployer to change it—it is therefore also not an RToken parameter.

  • Target unit: each collateral token in an RToken basket is expected to generally be stable or appreciating against some exogenous currency. The exogenous currency is that collateral's target unit. We expect that in many RTokens that people actually want, all of those target units will be the same, and we can speak of the RToken maintaining stability or appreciation against its target unit.

  • Reference unit: when collateral tokens are expected to appreciate, it's generally because some DeFi protocol produces a “receipt token” that is freely redeemable for some base token, the redemption rate of which is expected to monotonically increase over time. That base token is the reference unit for the collateral token.

A couple examples:

  • For a Compound collateral token such as cUSDC, the unit of account is USD, the reference unit USDC and target unit USD.
  • For an Aave collateral token such as aUSDP, the unit of account is USD, the reference token USDP and target unit USD.
  • Let's say we're building a pure-stable USD basket, out of USDC, USDP, and DAI. The unit of account would surely be USD. Each collateral token would also be its own reference unit, and their target units would be USD.

Reserve Protocol expects collateral tokens (e.g. cUSDC) to be in a known, predictable relationship with the reference units (e.g. USDC), and the reference units to be in a known, predictable relationship with the target units (e.g. USD) and will flag the collateral token as defaulting if any of these relationships appear to be broken.

Basket Dynamics

“Baskets” in the Reserve Protocol are arrays of financial values that the protocol references when keeping RTokens fully collateralized at all times. We differentiate between the following three types of baskets:

  • Prime basket: This is the target collateral basket at the onset of an RToken that defines which collateral needs to be deposited for issuances. The prime basket is directly set by governance, and only changes through successful governance proposals. It consists of an array of triples (<collateral token, target unit, target amount>) where each portion of the basket has a target amount of the target unit that should be represented by collateral token.

    For example, if the prime basket contains the triple <cUSDC, USD, 0.33>, that means "The RToken should contain 0.33 USD per basket, as represented by cUSDC".

  • Reference basket: When the prime basket is updated by governance or in the case of a collateral default, the protocol will determine a new “Reference Basket” and then take certain actions (described in the Protocol Operations section) to change the collateral makeup until it matches the new basket. This new basket is called the reference basket and, like the prime basket, consists of a set of triples <collateral token, reference unit, reference amount>. Each triple means that each basket unit must contain an amount of collateral token currently equivalent to reference amount of the reference unit.

    For example, if the reference basket contains the triple <aDAI, DAI, 0.33>, then one basket unit should contain whatever amount of aDAI is redeemable in its protocol for 0.33 DAI.

  • Collateral basket: the collateral basket is derived, moment-by-moment and on-demand, from the reference basket. Since DeFi redemption rates can change every transaction, so can the collateral basket. The collateral basket is a set of pairs <collateral token, token amount>. Each pair means that each basket unit must contain token amount of collateral token.

    For example, if the reference basket contains the pair <cUSDC, O.29>, then one basket unit will contain 0.29 cUSDC.

System States and Roles

Reserve Protocol contains five core governance roles that any governance smart contract can easily integrate in order to create new governance systems for RTokens:

  • OWNER: the top level decision maker, typically a decentralized governance smart contract, responsible for setting or updating all RToken parameter values, RToken baskets, etc. - The RToken OWNER has the power to:
  • grant and revoke roles to any Ethereum account
  • set governance parameters
  • upgrade system contracts
  • PAUSER: has the ability to pause and unpause an RToken’s system. The PAUSER role should be assigned to an address that is able to act quickly in response to off-chain events, such as a Chainlink feed failing. It is ok to have multiple pausers. It can be robot-controlled. It can also consist of a 1-of-N multisig for high availability and coverage. It is acceptable for there to be false positives, since redemption remains enabled. See the table below for more information on what exactly a “pause” of an RToken means.
  • SHORT_FREEZER: has the ability to freeze an RToken’s system for a short period of time. The SHORT_FREEZER role should be assigned to an address that might reasonably be expected to be the first to detect a bug in the code and can act quickly, and with some tolerance for false positives, though less than in pausing. It is acceptable to have multiple short freezers. It can be robot-controlled. It can also consist of a 1-of-N multisig for high availability and coverage. If a bug is detected, a short freeze can be triggered which will automatically expire if it is not renewed by LONG_FREEZER.
    When the SHORT_FREEZER call freezeShort(), they relinquish their SHORT_FREEZER role, and can only be re-granted the role by the OWNER (governance). The OWNER may also step in and unfreeze at any time.
  • LONG_FREEZER: has the ability to freeze an RToken’s system for a long period of time. The LONG_FREEZER role should be assigned to an address that will highly optimize for no false positives. It is much longer than the short freeze. It can act slowly and needs to be trusted. It is probably expected to have only one long-freezer address. It allows only 6x uses per long-freezer. It exists so that in the case of a zero-day exploit, governance can act before the system unfreezes and resumes functioning.
    When the LONG_FREEZER calls freezeLong(), they spend a “charge”. A LONG_FREEZER starts with 6 charges, and when they run out of charges they relinquish the LONG_FREEZER role. Only the OWNER can re-grant the role or top up an accounts charges.
  • GUARDIAN: has the ability to reject proposals even if they pass. Should be assigned to a multisig or EOA that can be trusted to act as a backstop. It is acceptable if it is relatively slow to act. Only one guardian address should be defined.

💡 While Reserve Protocol is a fully open system that allows the integration of any custom governance smart contract for RTokens, the Reserve team has deployed a recommended governance system that will be suggested to RToken deployers. If you’re interested in reading about its details, please refer to the Governor Alexios.

The roles mentioned above each have the ability to put their RToken’s system in specific non fully functional states in the case of an attack, exploit, or bug. These states are:

  • Paused: when an RToken’s system is paused, all interactions besides redemption, ERC20 functions, staking of RSR, and rewards payout are disabled. An RToken’s system can be paused by any of the Pauser addresses calling pause() and resumed by calling unpause().
  • Frozen: when an RToken’s system is frozen, all interactions besides ERC20 functions and staking of RSR are disabled. An RToken’s system can be short-frozen by any of the SHORT_FREEZER addresses calling shortfreeze(). This freeze can be extended by any of the LONG_FREEZER addresses calling longfreeze(), or can be resumed by the SHORT_FREEZER or OWNER addresses by calling unfreeze().

Deployed Rtokens

Deployed contracts