A permissionless platform to launch and govern asset-backed stable currencies.
Platform: Code4rena
Start Date: 06/01/2023
End Date: 20/01/2023
Period: 14 days
Status: Completed
Pot Size: $210,500 USDC
Participants: 73
Reporter: liveactionllama
Judge: 0xean
Id: 203
League: ETH
HollaDieWaldfee | 1/73 | $26,021.41 | 8 | 1 | 0 | 6 | 4 | Grade A | 0 | 0 |
0xA5DF | 2/73 | $17,645.80 | 6 | 1 | 0 | 3 | 2 | Grade B | Grade B | 0 |
0x52 | 3/73 | $14,727.23 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
unforgiven | 4/73 | $11,816.64 | 5 | 0 | 0 | 5 | 2 | 0 | 0 | 0 |
Cyfrin | 5/73 | $9,913.42 | 4 | 0 | 0 | 2 | 2 | - | - | 0 |
Soosh | 6/73 | $8,940.36 | 4 | 0 | 0 | 3 | 1 | Grade A | 0 | 0 |
severity | 7/73 | $5,335.79 | 2 | 0 | 0 | 2 | 1 | 0 | 0 | 0 |
wait | 8/73 | $4,676.19 | 2 | 0 | 0 | 2 | 1 | 0 | 0 | 0 |
AkshaySrivastav | 9/73 | $4,490.61 | 2 | 0 | 0 | 1 | 1 | 0 | Grade B | 0 |
csanuragjain | 10/73 | $4,418.17 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
Auditor per page
The C4audit output for the contest can be found here within an hour of contest opening.
Note for C4 wardens: Anything included in the C4udit output is considered a publicly known issue and is ineligible for awards.
Items listed below aren't necessarily issues but rather just describe some protocol specific behavior that we are aware of.
Additionally, anything mentioned in the previous audits is considered known issues:
The Reserve Protocol allows anyone to create stablecoins backed by baskets of ERC20 tokens on Ethereum. Stable asset backed currencies launched on the Reserve protocol are called “RTokens”.
Once an RToken configuration has been deployed, RTokens can be minted by depositing the entire basket of collateral backing tokens, and redeemed for the entire basket as well. Thus, an RToken will tend to trade at the market value of the entire basket that backs it, as any lower or higher price could be arbitraged.
RTokens can be overcollateralized, which means that if any of their collateral tokens default, there's a pool of value available to make up for the loss. RToken overcollateralization is provided by Reserve Rights (RSR) holders, who may choose to stake their RSR on any RToken. Staked RSR can be seized in the case of a collateral default, in a process that is entirely mechanistic based on on-chain price-feeds, and does not depend on any governance votes or human choices.
RTokens can generate revenue, and this revenue is the incentive for RSR holders to stake. Revenue can come from yield from lending collateral tokens on-chain or revenue shares with collateral token issuers. Governance can direct any portion of revenue to RSR stakers, to incentivize RSR holders to stake and provide overcollateralization. If an RToken generates no revenue, or if none of it is directed to RSR stakers, it probably won't have any RSR staked on it, and thus won't be protected by overcollateralization.
The protocol
folder in this repo is linked to the primary Reserve Protocol public repo at commit hash df7ecadc2bae74244ace5e8b39e94bc992903158
.
The base directory is assumed to be protocol
relative to the root of this repo.
The following directories and implementations are considered in-scope for this audit.
Contract | Purpose |
---|---|
contracts/p1/** | P1 Implementation of the Protocol |
contracts/libraries/** | Libraries used in the Protocol |
contracts/interfaces/** | Interfaces used in the Protocol |
contracts/mixins/** | Mixins used in the Protocol |
contracts/p1/mixins/** | Mixins used in the Protocol |
contracts/plugins/** | Plugins used in the Protocol |
For the P1 Implementation, here's a brief description of each file.
Contract | SLOC | Purpose | Libraries used |
---|---|---|---|
AssetRegistry.sol | 93 | Asset Registry | @openzeppelin/* |
BackingManager.sol | 138 | Backing Manager | @openzeppelin/* |
BasketHandler.sol | 351 | Basket Handler | @openzeppelin/* |
Broker.sol | 87 | Broker | @openzeppelin/* |
Deployer.sol | 177 | Deployer | @openzeppelin/* |
Distributor.sol | 110 | Distributor | @openzeppelin/* |
Furnace.sol | 46 | Furnace | @openzeppelin/* |
Main.sol | 42 | Main | @openzeppelin/* |
RevenueTrader.sol | 60 | Revenue Trader (used for both RSR Trader & RToken Trader) | @openzeppelin/* |
RToken.sol | 387 | RToken | @openzeppelin/* |
StRSR.sol | 398 | StRSR | @openzeppelin/* |
StRSRVotes.sol | 162 | StRSRVotes | @openzeppelin/* |
The following directories and implementations are considered out-of-scope for this audit.
Contract | Purpose |
---|---|
contracts/facade/** | Periphery Contracts for the Protocol |
contracts/p0/** | P0 Implementation of the Protocol |
We do have some very specific Recollateralization Logic described in the docs/recollateralization.md
file, you can also find other documentation in the same folder. There's additional information available in the primary README.md
file as well. Here's a video walkthrough of the code which provides additional context around specific files, structure and logic.
Additionally, we also recommend going through the following documents in order to understand the protocol better.
docs/system-design.md
docs/collateral.md
docs/Token Flow.png
docs/solidity-style.md
Fixed.sol
which describes our uint192
based fixed-point decimal value.- If you have a public code repo, please share it here: https://github.com/reserve-protocol/protocol - How many contracts are in scope?: 77 - Total SLoC for these contracts?: 5460 - How many external imports are there?: 35 - How many separate interfaces and struct definitions are there for the contracts within scope?: 27 structs, 42 interfaces - Does most of your code generally use composition or inheritance?: The main structure of the protocol is divided up with contract composition, though inheritance is used basically everywhere, in moderation. - How many external calls?: 12 - What is the overall line coverage percentage provided by your tests?: 95 - Is there a need to understand a separate part of the codebase / get context in order to audit this part of the protocol?: false - Please describe required context: - Does it use an oracle?: true; Specific Asset and Collateral plugins use oracles heavily; the main body of the protocol treats that as an implementation detail. Built-in assets use Chainlink oracles; other assets (if they’re canonical by the time this review is happening) are likely to use other oracles. - Does the token conform to the ERC20 standard?: The present tokens are ERC20s, yes. - Are there any novel or unique curve logic or mathematical models?: Not precisely what you’re asking, but it’ll be important to understand: 1) Basically everything in https://github.com/reserve-protocol/protocol/blob/master/docs/solidity-style.md, some of which is unique to us 2) Our system of Collateral units, described here: https://github.com/reserve-protocol/protocol/blob/master/docs/collateral.md#accounting-units-and-exchange-rates - Does it use a timelock function?: No - Is it an NFT?: No - Does it have an AMM?: No, though it does allow the permissionless launching of Gnosis EasyAuctions - Is it a fork of a popular project?: false - Does it use rollups?: false - Is it multi-chain?: false - Does it use a side-chain?: false
Clone the repo with the following command:
git clone --recurse-submodules https://github.com/code-423n4/2023-01-reserve.git
If you've already cloned the repo but without the --recurse-submodules
, you can run the following in the repo's directory:
git submodule update --init
Detailed steps to run tests against the protocol are available here in the docs/dev-env.md document:
yarn compile
yarn test:fast
yarn test:p0
yarn test:p1
yarn test:plugins
yarn test:integration
yarn test:coverage
To take gas measurements you can use the command yarn test:gas
which runs both the core protocol and integration tests in series.
To run tests with gas reporting for the core protocol, you can use yarn test:gas:protocol
which runs offline without a fork. In order to run integration tests with gas reporting, you can use yarn test:gas:integration
which requires a FORK to be set up.
This performs the following actions:
REPORT_GAS=1
env variablehardhat-gas-reporter
--parallel
flagdescribeGas
, which take gas measurements and compares them to a previous snapshot.It is important to remark that if you make changes to the contracts, and run the tests again with REPORT_GAS=1
, the tests will fail if the new gas cost differs from the one saved in the snapshot. Snapshots have to be recreated in each run by simply deleting the __snapshots__
folders located in \test
, \test\plugins
. and test\scenarios
, and running the tests again.
NOTES:
Exception: There are two tests within test\scenarios\MaxBasketSize.test.ts
that will fail when running the gas commands above for the complete test suite. This occurs because we take snapshots on a file by file basis, and gas costs differ when ran all together. So don't worry about those failures. To run gas measurements for this specific test file you can simply run:
PROTO_IMPL=1 REPORT_GAS=1 npx hardhat test test/scenario/MaxBasketSize.test.ts
.
If our process of using snapshots
is too cumbersome and adds a lot of friction to the way you do gas measurements, you can simply remove all sections in the tests identified as describeGas
, and use your own gas measurements and tools. At then end we can restore those and run the tests once just to save the updated final snapshot value. But we don't enforce any particular process for gas analysis so feel free to use what's best for you.
slither .
won't work, you need to run yarn slither