Showing preview only (1,499K chars total). Download the full file or copy to clipboard to get everything.
Repository: 0xNazgul/fuzzydefi
Branch: main
Commit: 89553188217c
Files: 196
Total size: 1.4 MB
Directory structure:
gitextract_drv2awpe/
├── CONTRIBUTING.md
├── LICENSE
├── PROPERTIES.md
├── README.md
├── package.json
└── protocols/
├── compound-v2/
│ ├── .gitignore
│ ├── .gitmodules
│ ├── LICENSE
│ ├── README.md
│ ├── foundry.toml
│ ├── package.json
│ ├── remappings.txt
│ ├── script/
│ │ └── Counter.s.sol
│ ├── src/
│ │ ├── BaseJumpRateModelV2.sol
│ │ ├── CDaiDelegate.sol
│ │ ├── CErc20.sol
│ │ ├── CErc20Delegate.sol
│ │ ├── CErc20Delegator.sol
│ │ ├── CErc20Immutable.sol
│ │ ├── CEther.sol
│ │ ├── CToken.sol
│ │ ├── CTokenInterfaces.sol
│ │ ├── Comptroller.sol
│ │ ├── ComptrollerG7.sol
│ │ ├── ComptrollerInterface.sol
│ │ ├── ComptrollerStorage.sol
│ │ ├── DAIInterestRateModelV3.sol
│ │ ├── EIP20Interface.sol
│ │ ├── EIP20NonStandardInterface.sol
│ │ ├── ErrorReporter.sol
│ │ ├── ExponentialNoError.sol
│ │ ├── Governance/
│ │ │ ├── Comp.sol
│ │ │ ├── GovernorAlpha.sol
│ │ │ ├── GovernorBravoDelegate.sol
│ │ │ ├── GovernorBravoDelegateG1.sol
│ │ │ ├── GovernorBravoDelegateG2.sol
│ │ │ ├── GovernorBravoDelegator.sol
│ │ │ └── GovernorBravoInterfaces.sol
│ │ ├── InterestRateModel.sol
│ │ ├── JumpRateModel.sol
│ │ ├── JumpRateModelV2.sol
│ │ ├── Lens/
│ │ │ └── CompoundLens.sol
│ │ ├── Maximillion.sol
│ │ ├── PriceOracle.sol
│ │ ├── Reservoir.sol
│ │ ├── SafeMath.sol
│ │ ├── SimplePriceOracle.sol
│ │ ├── Timelock.sol
│ │ ├── Unitroller.sol
│ │ └── WhitePaperInterestRateModel.sol
│ └── test/
│ ├── core.t.sol
│ └── mocks/
│ └── ERC20.sol
├── olympus-v1/
│ ├── .gitignore
│ ├── .gitmodules
│ ├── LICENSE
│ ├── README.md
│ ├── foundry.toml
│ ├── package.json
│ ├── remappings.txt
│ ├── script/
│ │ └── Counter.s.sol
│ ├── src/
│ │ ├── BondDepository.sol
│ │ ├── CVXBondDepository.sol
│ │ ├── OlympusERC20.sol
│ │ ├── RedeemHelper.sol
│ │ ├── RiskFreeValueOfNonReserve.sol
│ │ ├── Staking.sol
│ │ ├── StakingDistributor.sol
│ │ ├── StakingHelper.sol
│ │ ├── StakingWarmup.sol
│ │ ├── StandardBondingCalculator.sol
│ │ ├── Treasury.sol
│ │ ├── mocks/
│ │ │ ├── DAI.sol
│ │ │ ├── Frax.sol
│ │ │ ├── MockBondDepository.sol
│ │ │ └── MockTreasury.sol
│ │ ├── sOlympusERC20.sol
│ │ ├── wETHBondDepository.sol
│ │ └── wOHM.sol
│ └── test/
│ ├── IUniswapV2Pair.sol
│ └── core.t.sol
├── tombfinance/
│ ├── .gitignore
│ ├── .gitmodules
│ ├── README.md
│ ├── foundry.toml
│ ├── remappings.txt
│ ├── script/
│ │ └── Counter.s.sol
│ ├── src/
│ │ ├── Distributor.sol
│ │ ├── DummyToken.sol
│ │ ├── Masonry.sol
│ │ ├── Migrations.sol
│ │ ├── Oracle.sol
│ │ ├── SimpleERCFund.sol
│ │ ├── TBond.sol
│ │ ├── TShare.sol
│ │ ├── TaxOffice.sol
│ │ ├── TaxOfficeV2.sol
│ │ ├── TaxOracle.sol
│ │ ├── Timelock.sol
│ │ ├── Tomb.sol
│ │ ├── Treasury.sol
│ │ ├── distribution/
│ │ │ ├── TShareRewardPool.sol
│ │ │ ├── TombGenesisRewardPool.sol
│ │ │ └── TombRewardPool.sol
│ │ ├── interfaces/
│ │ │ ├── IBasisAsset.sol
│ │ │ ├── IDecimals.sol
│ │ │ ├── IDistributor.sol
│ │ │ ├── IERC20.sol
│ │ │ ├── IMasonry.sol
│ │ │ ├── IOracle.sol
│ │ │ ├── IShare.sol
│ │ │ ├── ISimpleERCFund.sol
│ │ │ ├── ITShareRewardPool.sol
│ │ │ ├── ITaxable.sol
│ │ │ ├── ITreasury.sol
│ │ │ ├── IUniswapV2Callee.sol
│ │ │ ├── IUniswapV2ERC20.sol
│ │ │ ├── IUniswapV2Factory.sol
│ │ │ ├── IUniswapV2Pair.sol
│ │ │ ├── IUniswapV2Router.sol
│ │ │ └── IWrappedFtm.sol
│ │ ├── lib/
│ │ │ ├── Babylonian.sol
│ │ │ ├── FixedPoint.sol
│ │ │ ├── Safe112.sol
│ │ │ ├── SafeMath8.sol
│ │ │ ├── UQ112x112.sol
│ │ │ ├── UniswapV2Library.sol
│ │ │ └── UniswapV2OracleLibrary.sol
│ │ ├── owner/
│ │ │ └── Operator.sol
│ │ └── utils/
│ │ ├── ContractGuard.sol
│ │ └── Epoch.sol
│ └── test/
│ ├── core.t.sol
│ ├── mocks/
│ │ ├── MockUniPair.sol
│ │ └── MockWeth.sol
│ └── v2-core/
│ ├── UniswapV2ERC20.sol
│ ├── UniswapV2Factory.sol
│ ├── UniswapV2Pair.sol
│ ├── interfaces/
│ │ ├── IUniswapV2Callee.sol
│ │ ├── IUniswapV2ERC20.sol
│ │ ├── IUniswapV2Factory.sol
│ │ └── IUniswapV2Pair.sol
│ ├── libraries/
│ │ ├── Math.sol
│ │ ├── SafeMath.sol
│ │ └── UQ112x112.sol
│ └── test/
│ └── ERC20.sol
└── uniswap-v2/
├── .gitignore
├── .gitmodules
├── README.md
├── foundry.toml
├── remappings.txt
├── script/
│ └── Counter.s.sol
├── src/
│ ├── UniswapV2ERC20.sol
│ ├── UniswapV2Factory.sol
│ ├── UniswapV2Pair.sol
│ ├── contracts/
│ │ ├── UniswapV2Migrator.sol
│ │ ├── UniswapV2Router01.sol
│ │ ├── UniswapV2Router02.sol
│ │ ├── examples/
│ │ │ ├── ExampleComputeLiquidityValue.sol
│ │ │ ├── ExampleFlashSwap.sol
│ │ │ ├── ExampleOracleSimple.sol
│ │ │ ├── ExampleSlidingWindowOracle.sol
│ │ │ ├── ExampleSwapToPrice.sol
│ │ │ └── README.md
│ │ ├── interfaces/
│ │ │ ├── IUniswapV2Migrator.sol
│ │ │ ├── IUniswapV2Router01.sol
│ │ │ ├── IUniswapV2Router02.sol
│ │ │ ├── IWETH.sol
│ │ │ └── V1/
│ │ │ ├── IUniswapV1Exchange.sol
│ │ │ └── IUniswapV1Factory.sol
│ │ ├── libraries/
│ │ │ ├── UniswapV2Library.sol
│ │ │ ├── UniswapV2LiquidityMathLibrary.sol
│ │ │ └── UniswapV2OracleLibrary.sol
│ │ └── test/
│ │ ├── DeflatingERC20.sol
│ │ ├── ERC20.sol
│ │ ├── RouterEventEmitter.sol
│ │ └── WETH9.sol
│ ├── interfaces/
│ │ ├── IERC20.sol
│ │ ├── IUniswapV2Callee.sol
│ │ ├── IUniswapV2ERC20.sol
│ │ ├── IUniswapV2Factory.sol
│ │ └── IUniswapV2Pair.sol
│ ├── libraries/
│ │ ├── AddressStringUtil.sol
│ │ ├── Babylonian.sol
│ │ ├── BitMath.sol
│ │ ├── FixedPoint.sol
│ │ ├── FullMath.sol
│ │ ├── Math.sol
│ │ ├── PairNamer.sol
│ │ ├── SafeERC20Namer.sol
│ │ ├── SafeMath.sol
│ │ ├── TransferHelper.sol
│ │ └── UQ112x112.sol
│ └── test/
│ ├── ERC20.sol
│ └── core.t.sol
└── test/
├── core.t.sol
└── mocks/
├── MockToken.sol
└── MockWETH.sol
================================================
FILE CONTENTS
================================================
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Fuzzy DeFi
First, thanks for your interest in contributing to this repository! I welcome and appreciate all contributions, including bug reports, feature suggestions, tutorials/blog posts, and code improvements.
If you're unsure where to start, I recommend taking a look at our [issue tracker](https://github.com/0xNazgul/FuzzyDeFi/issues). If you find an issue or proposal that you feel you can do, assign yourself to it.
## Bug reports and feature suggestions
Bug reports and feature suggestions can be submitted to our issue tracker. For bug reports, adding as much information as you can will help me in debugging and resolving the issue quickly.
## Questions
Questions can be submitted to the issue tracker or message me on twitter [@0xNazgul](https://twitter.com/0xNazgul).
## Code
This repository uses the pull request contribution model. Please create an account on Github if you don't have one already, fork this repository, and submit your contributions via pull requests. For more documentation, look [here](https://guides.github.com/activities/forking/).
Some pull request guidelines:
- Create a new branch from the [`main`](https://github.com/0xNazgul/FuzzyDeFi/tree/main) branch. If you are submitting a new feature, prefix the new branch name with `dev` (for example, `dev-add-properties-for-erc20-transfers`). If your submission is a bug fix, prefix the new branch name with `fix` (for example, `fix-typo-in-readme`). Please be descriptive in the branch name, avoid confusing or unclear names such as `mypatch2` or `bugfix`.
- Minimize irrelevant changes (formatting, whitespace, etc) to code that would otherwise not be touched by this patch. Save formatting or style corrections for a separate pull request that does not make any semantic changes.
- When possible, large changes should be split up into smaller focused pull requests.
- Fill out the pull request description with a summary of what your patch does, key changes that have been made, and any further points of discussion, if applicable. If your pull request solves an open issue, add "Fixes #xxx" at the end.
- Title your pull request with a brief description of what it's changing. "Fixes #123" is a good comment to add to the description, but makes for an unclear title on its own.
- If your are unsure about something, don't hesitate to ask!
## Adding a new protocol or invariant to another protocol
When adding a new protocol make sure to follow the [Directory Structure](#directory-structure), [Test File Structure](#test-file-structure) and [Properties Structure](#properties-structure). Explicitly note the required setup in a `README.md` file. I don't require you to add your own protocol notes in that same `README.md` file if you don't want to or if you just didn't.
When adding a new invariant make sure to follow the [Test File Structure](#test-file-structure) (specifically the testFuzz function format) and [Properties Structure](#properties-structure).
## Directory Structure
Below is a rough outline of the directory structure:
```text
.
├── protocols # Parent folder for contracts
│ ├── uniswap-v2 # Properties for Uniswap-v2 contracts
│ │ ├── lib # Required dependencies
│ │ ├── script # Scripts if any, mostly empty
│ │ ├── src # All slightly modified Project contracts
│ │ ├── test # Location of test files
│ │ │ ├── mocks # Any other mocks you may need
│ │ │ └── core.t.sol # Core test file with all properties
│ │ └── ... # Other testing specific files
│ ├── Olympus DAO # Properties for Olympus DAO contracts
│ │ └── ... # Same format
│ └── Other protocols
└── ...
```
Please follow this structure in your collaborations.
## Test File Structure
Below is a rough outline of the test file structure:
```Solidity
// SPDX-License-Identifier: UNLICENSED
// Adjust pragma version as needed
pragma solidity >=0.6.0;
// Test Helpers
import "forge-std/Test.sol";
// Import protocol files as needed
// Name should remain CoreTest
contract CoreTest is Test {
uint256 MAX = type(uint256).max;
function setUp() public {
// Add your own signature name if you want
vm.label(address(this), "THE_FUZZANATOR");
// Setup protocol contracts as needed
}
// Used to make sure contracts are deploying correctly
function testON() public {}
/* INVARIANTS: FUNCTION_NAME should:
* Invariant 1
* Invariant 2
* ...
*/
function testFuzz_FUNCTION_NAME() public {
// PRECONDITIONS:
// Anything that needs to be done prior to the action.
// Values that need to be fetched and stored into memory before the action
uint256 amount = _between(_amount, 1, MAX);
// ACTION:
// Calling the function to be fuzzed
try Contract.FUNCTION_NAME() {
// POSTCONDTIONS:
// Values that need to be fetched again after the action
// assert invariant conditions hold
assertEq(a, b, "A IS EQUAL TO B CHECK");
// Catch any overflow. Depending on what is being tested comment out assert(false) or assert properly
} catch {/*assert(false)*/ }// overflow
}
// Bounding function similar to vm.assume but is more efficient regardless of the fuzzing framework
// This is also a guarantee bound of the input unlike vm.assume which can only be used for narrow checks
function _between(uint256 random, uint256 low, uint256 high) public pure returns (uint256) {
return low + random % (high-low);
}
}
```
Please follow this structure in your collaborations.
## Properties Structure
Below is a rough outline of the properties file structure:
| ID | Name | Invariant tested |
| --- | --- | --- |
BLA-001 | [testFuzz_FUNCTIONNAME]() | FUNCTIONNAME should: <ul><li>Invariant 1</li><li>Invariant 2</li><li>...</li></ul>
BLA-002 | [testFuzz_FUNCTIONNAME2]() | FUNCTIONNAME2 should: <ul><li>Invariant 1</li><li>Invariant 2</li><li>...</li></ul>
... | ... | ...
Please follow this structure in your collaborations.
## Protocol Notes
These are mostly for myself to get a stronger understanding of how the protocol works. If you want add more useful information or maybe I misunderstood something. Feel free to submit an issue or a PR updating those readme files.
================================================
FILE: LICENSE
================================================
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
================================================
FILE: PROPERTIES.md
================================================
# Introduction
Here is a list of the property tests for the top five forked protocols. For each property, there is a permalink to the file implementing it in the repository and a small description of the invariant tested.
This may not be a complete list and there may be some more invariants to test. I focused more on functions that transferred funds or of major state updates. Also note that there are still some invariants listed here that needs to be implemented. Within each project folder `README.md` one can find what is left under `Invariants TODO` section.
## Table of contents
- [Introduction](#introduction)
- [Table of contents](#table-of-contents)
- [Uniswap v2](#uniswap-v2)
- [Olympus DAO](#olympus-dao)
- [Compound v2](#compound-v2)
- [Tomb Finance](#tomb-finance)
## Uniswap v2
| ID | Name | Invariant tested |
| --- | --- | --- |
UNI-001 | [testFuzz_AddLiq](/protocols/uniswap-v2/src/test/core.t.sol#L88) | Adding liquidity to a pair should: <ul><li>Increase reserves</li><li>Increase address to balance</li><li>Increase totalSupply</li><li>Increase k</li></ul>
UNI-002 | [testFuzz_ETHAddLiq](/protocols/uniswap-v2/src/test/core.t.sol#L124) | Same as adding liquidity
UNI-003 | [testFuzz_RemoveLiq](/protocols/uniswap-v2/src/test/core.t.sol#L161) | Removing liquidity from a pair should: <ul><li>Decrease reserves</li><li>Decrease address to balance</li><li>Decrease totalSupply</li><li>Decrease K</li></ul>
UNI-004 | [testFuzz_ETHRemoveLiq](/protocols/uniswap-v2/src/test/core.t.sol#L199) | Same as removing liquidity
UNI-005 | [testFuzz_removeLiqWithPermit](/protocols/uniswap-v2/src/test/core.t.sol#L237) | Same as removing liquidity
UNI-006 | [testFuzz_removeLiquidityETHWithPermit](/protocols/uniswap-v2/src/test/core.t.sol#L124) | Same as removing liquidity
UNI-007 | [testFuzz_removeLiqETHSupportingFeeOnTransferTokens](/protocols/uniswap-v2/src/test/core.t.sol#L415) | Same as removing liquidity
UNI-008 | [testFuzz_removeLiqETHWithPermitSupportingFeeOnTransferTokens](/protocols/uniswap-v2/src/test/core.t.sol#L453) | Same as removing liquidity
UNI-009 | [testFuzz_swapExactTokensForTokens](/protocols/uniswap-v2/src/test/core.t.sol#L541) | Swapping within a pair should: <ul><li>Decrease balance of user for token 2</li><li>Increase balance of user for token 1</li><li>Decrease/leave k unchanged</li></ul>
UNI-010 | [testFuzz_swapExactETHForTokens](/protocols/uniswap-v2/src/test/core.t.sol#L582) | Same as Swap
UNI-011 | [testFuzz_swapTokensForExactETH](/protocols/uniswap-v2/src/test/core.t.sol#L625) | Same as Swap
UNI-012 | [testFuzz_swapExactTokensForETH](/protocols/uniswap-v2/src/test/core.t.sol#L668) | Same as Swap
UNI-013 | [testFuzz_swapETHForExactTokens](/protocols/uniswap-v2/src/test/core.t.sol#L711) | Same as Swap
UNI-014 | [testFuzz_swapExactTokensForTokensSupportingFeeOnTransferTokens](/protocols/uniswap-v2/src/test/core.t.sol#L754) | Same as Swap
UNI-015 | [testFuzz_swapExactETHForTokensSupportingFeeOnTransferTokens](/protocols/uniswap-v2/src/test/core.t.sol#L796) | Same as Swap
UNI-016 | [testFuzz_swapExactTokensForETHSupportingFeeOnTransferTokens](/protocols/uniswap-v2/src/test/core.t.sol#L842) | Same as Swap
## Olympus DAO
| ID | Name | Invariant tested |
| --- | --- | --- |
OLY-001 | [testFuzz_deposit](/protocols/olympus-v1/test/core.t.sol#L163) | Depositing into the BondDepo should:<ul><li>Increase user Bond Payout</li><li>Updates users last block to latest</li><li>Updates Bond Price</li><li>Increase Total Debt</li><li>Increase Treasury Total Reserves</li><li>Updates control variable accordingly</li><li>Updates rate accordingly</li></ul>
OLY-002 | [testFuzz_redeemNoStaking](/protocols/olympus-v1/test/core.t.sol#L204) | Redeeming without staking from BondDepo should:<ul><li>Decrease user payout</li><li>Decrease user vesting</li><li>Update user lastBlock</li><li>Increase user OHM Balance</li></ul>
OLY-003 | [testFuzz_redeemWith](/protocols/olympus-v1/test/core.t.sol#L256) | Redeeming with staking from BondDepo should:<ul><li>Decrease user payout</li><li>Decrease user vesting</li><li>Update user lastBlock</li><li>Increase staking OHM Balance</li><li>Increase staking warmup sOHM Balance</li><li>Increase user staking deposit</li><li>Increase user gons</li><li>Increase user expiry</li><li>Update user lock to false</li></ul>
OLY-004 | [testFuzz_redeemRebase](/protocols/olympus-v1/test/core.t.sol#L305) | Redeeming from BondDepo should:<ul><li>Updates distribute</li><li>Increases number</li><li>Increases endBlock</li></ul>
OLY-005 | [testFuzz_unstake](/protocols/olympus-v1/test/core.t.sol#L335) | Unstaking should:<ul><li>Increase user OHM balance</li><li>Decrease user sOHM balance</li><li>Increase Staking sOHM balance</li><li>Decrease Staking OHM balance</li></ul>
## Compound v2
| ID | Name | Invariant tested |
| --- | --- | --- |
COM-001 | [testFuzz_mint](/protocols/compound-v2/test/core.t.sol#L126) | Calling mint Should: <ul><li>Increase cToken TotalSupply</li><li>Increase User cToken Balance</li><li>Decrease User underlying Balance</li><li>Update Supply Index in Comptroller</li><li>Update Comp Supplier Index in Comptroller</li><li>Update supplier compAccrued in Comptroller</li><li>Update Supply block Number in Comptroller</li><li>Update cToken accrualBlockNumber</li><li>Update cToken borrowIndex</li><li>Update cToken totalBorrows</li><li>Update cToken totalReserves</li></ul>
COM-002 | [testFuzz_redeem](/protocols/compound-v2/test/core.t.sol#L178) | Calling redeem Should:<ul><li>Decrease cToken TotalSupply</li><li>Decrease User cToken Balance</li><li>Increase User underlying Balance</li><li>Update Supply Index in Comptroller</li><li>Update Comp Supplier Index in Comptroller</li><li>Update supplier compAccrued in Comptroller</li><li>Update Supply block Number in Comptroller</li><li>Update cToken accrualBlockNumber</li><li>Update cToken borrowIndex</li><li>Update cToken totalBorrows</li><li>Update cToken totalReserves</li></ul>
COM-003 | [testFuzz_borrow](/protocols/compound-v2/test/core.t.sol#L239) | Calling borrow Should:<ul><li>Update borrow index in Comptroller</li><li>Update borrow block in Comptroller</li><li>Update borrower compAccrued in Comptroller</li><li>Update compBorrowerIndex in Comptroller</li><li>Add user to market in Comptroller</li><li>Add cToken to users accountAssets in Comptroller</li><li>Increase accountBorrows principal</li><li>Update accountBorrows interestIndex</li><li>Increase totalBorrows</li><li>Increase User underlying Balance</li></ul>
COM-004 | [testFuzz_repayBorrow](/protocols/compound-v2/test/core.t.sol#L295) | Calling repayBorrow Should:<ul><li>Update borrow index in Comptroller</li><li>Update borrow block in Comptroller</li><li>Update borrower compAccrued in Comptroller</li><li>Update compBorrowerIndex in Comptroller</li><li>Add user to market in Comptroller</li><li>Add cToken to users accountAssets in Comptroller</li><li>Increase accountBorrows principal</li><li>Update accountBorrows interestIndex</li><li>Increase totalBorrows</li><li>Increase User underlying Balance</li></ul>
COM-005 | [testFuzz_liquidateBorrow](/protocols/compound-v2/test/core.t.sol#L416) | Calling liquidateBorrow Should:<ul><li>Update cToken accrualBlockNumber</li><li>Update cToken borrowIndex</li><li>Update cToken totalBorrows</li><li>Increase totalReserves</li><li>Decrease cToken totalSupply</li><li>Decrease borrower accountTokens</li><li>Increase liquidator accountTokens</li></ul>
COM-006 | [testFuzz_repayBorrowBehalf](/protocols/compound-v2/test/core.t.sol#L356) | Calling repayBorrowBehalf Should:<ul><li>Update borrow index in Comptroller</li><li>Update borrow block in Comptroller</li><li>Update borrower compAccrued in Comptroller</li><li>Update compBorrowerIndex in Comptroller</li><li>Add user to market in Comptroller</li><li>Add cToken to users accountAssets in Comptroller</li><li>Increase accountBorrows principal</li><li>Update accountBorrows interestIndex</li><li>Increase totalBorrows</li><li>Increase User underlying Balance</li></ul>
COM-007 | [testFuzz_sweepToken](/protocols/compound-v2/test/core.t.sol#L474) | Calling sweepToken Should:<ul><li>Decrease ctoken random token balance</li><li>Increase Admin random token balance</li></ul>
COM-008 | [testFuzz_addReserves](/protocols/compound-v2/test/core.t.sol#L504) | Calling addReserves Should:<ul><li>Update cToken accrualBlockNumber</li><li>Update cToken borrowIndex</li><li>Update cToken totalBorrows</li><li>Update cToken totalReserves (after accrueInterest)</li><li>Decease User balance</li><li>Increase ctoken underlying balance</li></ul>
COM-009 | [testFuzz_transfer](/protocols/compound-v2/test/core.t.sol#L537) | Calling transfer Should:<ul><li>Decrease from address accountTokens</li><li>Increase to address accountTokens</li></ul>
COM-010 | [testFuzz_transferFrom](/protocols/compound-v2/test/core.t.sol#L566) | Calling transferFrom Should:<ul><li>Decrease from address accountTokens</li><li>Increase to address accountTokens</li></ul>
## Tomb Finance
| ID | Name | Invariant tested |
| --- | --- | --- |
TMF-001 | [testFuzz_tombMint](/protocols/tombfinance/test/core.t.sol#L182) | Tomb mint should: <ul><li>Increase User Balance</li><li>Increase Total Supply</li>
TMF-002 | [testFuzz_tombBurn](/protocols/tombfinance/test/core.t.sol#L203) | Tomb burn should:<ul><li>Decrease User Balance</li><li>Decrease Total Supply</li>
TMF-003 | [testFuzz_tombBurnFrom](/protocols/tombfinance/test/core.t.sol#L228) | Tomb burnFrom should:<ul><li>Decrease User Balance</li><li>Decrease Total Supply</li>
TMF-004 | [testFuzz_tombTransferFrom](/protocols/tombfinance/test/core.t.sol#L254) | Tomb transferFrom without `autoCalculateTax & currentTaxRate == 0` should:<ul><li>Decrease from User Balance</li><li>Increase to User Balance</li><li>Total Supply should remain the same</li>
TMF-005 | [testFuzz_tombTaxTransferFrom](/protocols/tombfinance/test/core.t.sol#L284) | Tomb transferFrom with autoCalculateTax should:<ul><li>Decrease from User Balance</li><li>Increase to User Balance</li><li>Decrease Total Supply</li>
TMF-006 | [testFuzz_tBondMint](/protocols/tombfinance/test/core.t.sol#L316) | TBond mint should:<ul><li>Increase User Balance</li><li>Increase Total Supply</li>
TMF-007 | [testFuzz_tBondBurn](/protocols/tombfinance/test/core.t.sol#L337) | TBond burn should:<ul><li>Decrease User Balance</li><li>Decrease Total Supply</li>
TMF-008 | [testFuzz_tBondBurnFrom](/protocols/tombfinance/test/core.t.sol#L362) | TBond burnFrom should:<ul><li>Decrease User Balance</li><li>Decrease Total Supply</li>
TMF-009 | [testFuzz_tombGenesisRewardPoolDeposit](/protocols/tombfinance/test/core.t.sol#L389) | Depositing into TombGenesisRewardPool Should: <ul><li>Update pool reward variables</li><li>Decrease User bal of token</li><li>Update User rewardDebt</li><li>Increase user bal amount</li></ul>
TMF-010 | [testFuzz_tombGenesisRewardPoolWithdraw](/protocols/tombfinance/test/core.t.sol#L430) | Withdrawing from TombGenesisRewardPool Should: <ul><li>Update pool reward variables</li><li>Increase User bal of token</li><li>Update User rewardDebt</li><li>Decrease user bal amount</li></ul>
TMF-011 | [testFuzz_tombGenesisRewardPoolEmergencyWithdraw](/protocols/tombfinance/test/core.t.sol#L372) | Emergency withdrawing from TombGenesisRewardPool Should: <ul><li>Increase User bal of token</li><li>Decrease User rewardDebt</li><li>Decrease user bal amount</li></ul>
TMF-012 | [testFuzz_tombGenesisRewardPooGovernanceRecoverUnsupported](/protocols/tombfinance/test/core.t.sol#L498) | TombGenesisRewardPool Governance recover Should: <ul><li>Decrease contract bal of token</li><li>Increase to User bal of token</li></ul>
TMF-013 | [testFuzz_tombRewardPoolDeposit]() | Depositing into TombRewardPool Should: <ul><li>Update pool reward variables</li><li>Decrease User bal of token</li><li>Increase User rewardDebt</li><li>Increase user bal amount</li></ul>
TMF-014 | [testFuzz_tombRewardPoolWithdraw](/protocols/tombfinance/test/core.t.sol#L541) | Withdrawing from TombRewardPool Should: <ul><li>Update pool reward variables</li><li>Increase User bal of token</li><li>Update User rewardDebt</li><li>Decrease user bal amount</li></ul>
TMF-015 | [testFuzz_tombRewardPoolEmergencyWithdraw](/protocols/tombfinance/test/core.t.sol#L582) | Emergency withdrawing from TombRewardPool Should: <ul><li>Increase User bal of token</li><li>Decrease User rewardDebt</li><li>Decrease user bal amount</li></ul>
TMF-016 | [testFuzz_tombRewardPoolGovernanceRecoverUnsupported](/protocols/tombfinance/test/core.t.sol#L650) | TombRewardPool Governance recover Should: <ul><li>Decrease contract bal of token</li><li>Increase to User bal of token</li></ul>
TMF-017 | [testFuzz_tShareRewardPoolDeposit](/protocols/tombfinance/test/core.t.sol#L694) | Depositing into TShareRewardPool Should: <ul><li>Update pool reward variables</li><li>Decrease User bal of token</li><li>Increase User rewardDebt</li><li>Increase user bal amount</li></ul>
TMF-018 | [testFuzz_tShareRewardPoolWithdraw](/protocols/tombfinance/test/core.t.sol#L735) | Withdrawing from TShareRewardPool Should: <ul><li>Update pool reward variables</li><li>Increase User bal of token</li><li>Update User rewardDebt</li><li>Decrease user bal amount</li></ul>
TMF-019 | [testFuzz_tShareRewardPoolEmergencyWithdraw](/protocols/tombfinance/test/core.t.sol#L777) | Emergency withdrawing from TShareRewardPool Should: <ul><li>Increase User bal of token</li><li>Decrease User rewardDebt</li><li>Decrease user bal amount</li></ul>
TMF-020 | [testFuzz_testFuzztShareRewardPoolGovernanceRecoverUnsupported](/protocols/tombfinance/test/core.t.sol#L803) | TShareRewardPool Governance recover Should: <ul><li>Decrease contract bal of token</li> <li>Increase to User bal of token</li></ul>
TMF-021 | [testFuzz_masonryStake](/protocols/tombfinance/test/core.t.sol#L845) | Staking into Masonry Should: <ul><li>Increase totalSupply</li><li>Increase User staked bal</li><li>Decrease User tBond amount</li></ul>
TMF-022 | [testFuzz_masonryWithdraw](/protocols/tombfinance/test/core.t.sol#L879) | Depositing into Masonry Should: <ul><li>Decrease totalSupply</li><li>Decrease User staked bal</li><li>Increase User tBond amount</li></ul>
TMF-023 | [testFuzz_masonryClaimReward](/protocols/tombfinance/test/core.t.sol#L919) | Claiming reward from Masonry Should: <ul><li>Decrease User Reward</li><li>Increase tomb bal</li><li>Update User epochTimerStart</li></ul>
TMF-024 | [testFuzz_masonryExit](/protocols/tombfinance/test/core.t.sol#L967) | Exiting from Masonry Should: <ul><li>Decrease totalSupply</li><li>Decrease User staked bal</li><li>Increase User tBond amount</li></ul>
TMF-025 | [testFuzz_masonryAllocateSeigniorage](/protocols/tombfinance/test/core.t.sol#L1007) | Masonry Allocate Seigniorage Should: <ul><li>Update nextRPS</li><li>Update time</li><li>Decrease from User tomb bal</li><li>Increase contracts tomb bal</li></ul>
TMF-026 | [testFuzz_masonryGovernanceRecoverUnsupported](/protocols/tombfinance/test/core.t.sol#L1013) | Masonry Governance recover Should: <ul><li>Decrease contract bal of token</li><li>Increase to User bal of token</li></ul>
TMF-027 | [testFuzz_treasuryBuyBonds](/protocols/tombfinance/test/core.t.sol#L1037) | Buying bonds from the Treasury Should: <ul><li>Decrease User tomb bal</li><li>Increase User tBond bal</li><li>Decrease epochSupplyContractionLeft</li></ul>
TMF-028 | [testFuzz_treasuryRedeemBonds](/protocols/tombfinance/test/core.t.sol#L1079) | Redeeming bonds from the Treasury Should: <ul><li>Decrease User tBond bal</li><li>Increase User tomb bal</li><li>Decrease epochSupplyContractionLeft</li></ul>
TMF-029 | [testFuzz_treasuryAllocateSeigniorage](/protocols/tombfinance/test/core.t.sol#L1120) | Treasury Allocate Seigniorage Should: <ul><li>Update previousEpochTombPrice</li><li>If `_savedForBond > 0`, increase contract tomb bal</li><li>If `_savedForMasonry > 0 && daoFundSharedPercent > 0` increase daoFund tomb bal</li><li>If `_savedForMasonry > 0 && devFundSharedPercent > 0` increase devFund tomb bal</li><li>Update masonry's allowance</li></ul>
TMF-030 | [testFuzz_treasuryGovernanceRecoverUnsupported](/protocols/tombfinance/test/core.t.sol#L1126) | Treasury Governance recover Should: <ul><li>Decrease contract bal of token</li><li>Increase to User bal of token</li></ul>
TMF-031 | [testFuzz_tShareClaimRewards](/protocols/tombfinance/test/core.t.sol#L1149) | tShare Claim rewards Should: <ul><li>Increase totalSupply</li><li>If `_pending > 0 && communityFund != address(0)` increase communityFund tShare bal</li><li>If `_pending > 0 && devFund != address(0)` increase devFund tShare bal</li></ul>
TMF-032 | [testFuzz_tShareBurn](/protocols/tombfinance/test/core.t.sol#L1191) | TShare Burn Should: <ul><li>Decrease User Balance</li><li>Decrease Total Supply</li></ul>
TMF-033 | [testFuzz_tShareGovernanceRecoverUnsupported](/protocols/tombfinance/test/core.t.sol#L1216) | Governance recover from TShare Should: <ul><li>Decrease contract bal of token</li><li>Increase to User bal of token</li></ul>
================================================
FILE: README.md
================================================
# Fuzzy DeFi
## Properties
This repository contains code properties for the current top four forked protocols:
1. [Uniswap v2](/protocols/uniswap-v2/README.md) An AMM powered by the constant product formula, [properties](/PROPERTIES.md#L15).
2. [Olympus DAO](/protocols/olympus-v1/README.md) A protocol-owned Treasury serving the market gap between stablecoins and volatile assets, [properties](/PROPERTIES.md#L36).
3. [Compound v2](/protocols/compound-v2/README.md#L46) An algorithmic, autonomous interest rate protocol, [properties](/PROPERTIES.md#L).
4. [Tomb Finance](/protocols/tombfinance/README.md) An algorithmic token pegged to `FTM`, [properties](/PROPERTIES.md#L60).
The goals of these properties are to:
* Detect vulnerabilities
* Ensure adherence to the original protocols properties
* Provide educational guidance for writing invariants
## Testing
1. Install [Foundry](https://book.getfoundry.sh/getting-started/installation)
2. Follow the protocols corresponding `README` setup.
## Contributing to this repo?
You can read more about the contribution guidelines and directory structure in the [CONTRIBUTING](/CONTRIBUTING.md) file.
## Trophies
I have not used it in the wild and did this mostly to build my fuzzing skills. If you use this and find any bugs congrats!!!
Create an issue with "Trophy" as your title and we can add it to a list with your proper credits!
## No Guarantees
There are no guarantees with using this project to secure your protocol! There is still a lot to improve with this repo and not everything is fully tested nor is it a silver bullet!
## License
Modified code forked from there respective companies are licensed under there respective licenses in accordance with the original licenses.
All other files within this repository are licensed under the AGPL License unless stated otherwise.
================================================
FILE: package.json
================================================
{
"name": "fuzzy-defi",
"version": "0.0.2",
"description": "Pre-built security properties for commonly forked DeFi protocols",
"repository": {
"type": "git",
"url": "git+https://github.com/0xNazgul/FuzzyDeFi.git"
},
"author": "0xNazgul",
"license": "MIT",
"bugs": {
"url": "https://github.com/0xNazgul/FuzzyDeFi/issues"
},
"homepage": "https://github.com/0xNazgul/FuzzyDeFi#readme"
}
================================================
FILE: protocols/compound-v2/.gitignore
================================================
cache
out
================================================
FILE: protocols/compound-v2/.gitmodules
================================================
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
branch = v1.7.1
================================================
FILE: protocols/compound-v2/LICENSE
================================================
Copyright 2020 Compound Labs, Inc.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: protocols/compound-v2/README.md
================================================
# Setup
1. `forge install`
2. `forge test --mc TestCore`
## Integration
1. Follow setup
2. Add test helpers functions:
| Contract | Function |
| --- | --- |
[CErc20.sol](./src/CErc20.sol) | [getCashPriorpub()](./src/CErc20.sol#L153)
3. Remove test helpers from contract before deploying
* I'm not responsible for what happens if you leave them in
# **Notes on Compound v2**
Compound was created on the bases of being a decentralized system for borrowing of token without flaws of existing approaches:
* Centralized exchanges
* Peer to peer protocols that have high costs and added frictions onto users
* Borrowing mechanisms were limited
* Assets having negative yield without natural interest rates to offset them.
It's meant to establish money markets (pools of tokens) with derived interest rates based on supply and demand for the token.
* Suppliers earn a floating interest rate without dealing with maturity, interest rate or collateral with a peer
* borrowers pay the floating interest rate without dealing with a peer
### **Supplying**:
Compound aggregates the supply of each user:
* When a user supplies a token it becomes a resource
* Offers liquidity
* Can withdraw at any time without loan maturity
Balances accrue interest based on the supply interest rate of the asset. When a user updates there balance, accrued interest is converted into principal and paid. This gives users with long-term investments a chance to gain additional returns.
### **Borrowing**:
Users can borrow using collateralized lines of credit. There are no specific terms and they only have to specify the wanted assets amount. The cost of such is determined by the floating interest rate set by the market.
* Each account must have a balance that covers the outstanding borrowed amount (collateral ratio).
* This can be brought below the ratio by borrowing or withdrawing
* This can be increased when users repay borrowed asset in whole or part at any time
* Balances held even being used as collateral still accrue interest
Users whose `(supplied assets / outstanding borrowing) < collateral ratio` leave their collateral and borrowed assets up for purchase at `(current market price - liquidation discount)`.
* Incentivizes arbitrageurs to reduce borrower's exposure and lower protocol's risk.
* Any user with the borrowed asset can liquidate in whole or part. Exchanging their asset for the borrower's collateral.
The main use of this is to be able to hold new assets without selling or rearranging a portfolio giving users abilities of:
* Not having to wait for order fills or off-chain behavior. Allowing dApps to borrow tokens to use.
* Traders can finance new ICO investments by borrowing and using their existing portfolio as collateral
* Traders can short token by borrowing it sending it to an exchange and sell the token
### **Interest Rate Model**:
The protocol achieves an efficient interest rate equilibrium for each market based on supply and demand of individual assets. This utilization ratio U unifies supply and demand into a single variable:
* `U = Borrows / (Cash + Borrows)`
Interest rates should increase as a function of demand:
* When demand is low rates should be low
* When demand is high rates should be high
This curve is codified through governance and updated by the chief economist. It is expressed as a function of utilization:
* `Borrowing interest Rate = 10% + U * 30%`
The total amount of interest earned by suppliers must be < total interest product by borrowers. Supply interest rate is a function of borrowing interest rate including a spread S representing the economic profit of the protocol:
* `Supply Interest Rate = Borrowing Interest Rate * U * (1 - S)`
### **cTokens**:
This is a EIP-20 compliant contract that keeps track of balances supplied to the protocol. Users can mint cTokens to earn interest from the cTokens exchange rate that increases in value relative to the asset. Users can also use the cTokens as collateral.
* All mints, redeems, borrow, repays a borrow, liquidates a borrow or transfers are done via the cToken.
* Two types of cTokens CErc20 (wraps the underlying ERC-20 asset)and CEther (wraps ether)
### **Comptroller**:
Comptroller is the risk management contract that determines the amount of collateral a user must have to maintain or if they can be liquidated. When a user interacts with a cToken the comptroller is asked to approve/deny it.
It also maps user balances to prices (price oracle) to risk weight for making the determinations. Users can list which assets they would like to include in their risk scoring.
### **Governance**:
The protocol is governed by COMP holders and has three components:
1. COMP token
2. Governance module by Governor Bravo
3. Timelock
These give COMP holders the ability to propose, vote and implement changes. Proposals can modify anything in the protocol. Holders can delegate to any address of their choice. Delegation has its limits where an address must have at least 25,000 COMP to create a proposal or any address can lock 100 COMP to create an Autonomous Proposal. This allows other users to delegate to it to crate a proposal after the 25,000 COMP is reached.
The proposal process is as follows:
* 2 day review period
* Voting weights are recorded and voting begins
* Voting last 3 days
* If a majority and at least 400,000 votes are cast for the proposal it is queued in the Timelock
* It can than be implemented 2 days later
* Total about one week
Comp itself is an ERC-20 token that has voting rights.
### **Open Price Feed**:
Accounts price data for the protocol and is used by the comptroller as a source of truth for prices. Compound uses a price feed to verify the reported prices are withing bounds of TWAP of the pair on Uniswap v2 (sanity check or Anchor price).
Chainlink price feeds submit prices for each cToken through an individual validatorProxy. This is the only valid reporter for the underlying asset price.
Open Price Feed has two main contracts:
1. ValidatorProxy which queries Uniswap v2 to check if the new price is within the TWAP anchor. If valid it updates the asset price and discards the price data elsewise
2. UiswapAnchoredView only stores prices withing the bound of the TWAP and are signed by a reporter. Handles upscaling prices into the comptroller formant.
Allows multiple views to use the same underlying price data and verify the prices in their own way.
* Stablecoins are fixed at $1. SAI is fixed at 0.005285 ETH.
* Compound multisig has the ability to switch market's primary oracle from Chainlink price feeds to uniswap v2 during a failover.
### **Extra Links**:
[Whitpaper](https://github.com/compound-finance/compound-money-market/blob/master/docs/CompoundWhitepaper.pdf)
[Protocol High level](https://github.com/compound-finance/compound-protocol/blob/master/docs/CompoundProtocol.pdf)
[Documents](https://docs.compound.finance/v2/)
### **Audit Links**:
[audits](https://docs.compound.finance/v2/security/)
================================================
FILE: protocols/compound-v2/foundry.toml
================================================
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
[fuzz]
runs = 10000
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
================================================
FILE: protocols/compound-v2/package.json
================================================
{
"name": "compound-protocol",
"version": "0.2.1",
"description": "The Compound Money Market",
"main": "index.js",
"repository": "git@github.com:compound-finance/compound-protocol.git",
"author": "Compound Finance",
"license": "UNLICENSED"
}
================================================
FILE: protocols/compound-v2/remappings.txt
================================================
forge-std/=lib/forge-std/src/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts
@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/openzeppelin-contracts/contracts
@compound/=src/
@rari-capital/solmate/=lib/solmate/
================================================
FILE: protocols/compound-v2/script/Counter.s.sol
================================================
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Script.sol";
contract CounterScript is Script {
function setUp() public {}
function run() public {
vm.broadcast();
}
}
================================================
FILE: protocols/compound-v2/src/BaseJumpRateModelV2.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./InterestRateModel.sol";
/**
* @title Logic for Compound's JumpRateModel Contract V2.
* @author Compound (modified by Dharma Labs, refactored by Arr00)
* @notice Version 2 modifies Version 1 by enabling updateable parameters.
*/
abstract contract BaseJumpRateModelV2 is InterestRateModel {
event NewInterestParams(uint baseRatePerBlock, uint multiplierPerBlock, uint jumpMultiplierPerBlock, uint kink);
uint256 private constant BASE = 1e18;
/**
* @notice The address of the owner, i.e. the Timelock contract, which can update parameters directly
*/
address public owner;
/**
* @notice The approximate number of blocks per year that is assumed by the interest rate model
*/
uint public constant blocksPerYear = 2102400;
/**
* @notice The multiplier of utilization rate that gives the slope of the interest rate
*/
uint public multiplierPerBlock;
/**
* @notice The base interest rate which is the y-intercept when utilization rate is 0
*/
uint public baseRatePerBlock;
/**
* @notice The multiplierPerBlock after hitting a specified utilization point
*/
uint public jumpMultiplierPerBlock;
/**
* @notice The utilization point at which the jump multiplier is applied
*/
uint public kink;
/**
* @notice Construct an interest rate model
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by BASE)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by BASE)
* @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point
* @param kink_ The utilization point at which the jump multiplier is applied
* @param owner_ The address of the owner, i.e. the Timelock contract (which has the ability to update parameters directly)
*/
constructor(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_, address owner_) internal {
owner = owner_;
updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);
}
/**
* @notice Update the parameters of the interest rate model (only callable by owner, i.e. Timelock)
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by BASE)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by BASE)
* @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point
* @param kink_ The utilization point at which the jump multiplier is applied
*/
function updateJumpRateModel(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_) virtual external {
require(msg.sender == owner, "only the owner may call this function.");
updateJumpRateModelInternal(baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_);
}
/**
* @notice Calculates the utilization rate of the market: `borrows / (cash + borrows - reserves)`
* @param cash The amount of cash in the market
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market (currently unused)
* @return The utilization rate as a mantissa between [0, BASE]
*/
function utilizationRate(uint cash, uint borrows, uint reserves) public pure returns (uint) {
// Utilization rate is 0 when there are no borrows
if (borrows == 0) {
return 0;
}
return borrows * BASE / (cash + borrows - reserves);
}
/**
* @notice Calculates the current borrow rate per block, with the error code expected by the market
* @param cash The amount of cash in the market
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market
* @return The borrow rate percentage per block as a mantissa (scaled by BASE)
*/
function getBorrowRateInternal(uint cash, uint borrows, uint reserves) internal view returns (uint) {
uint util = utilizationRate(cash, borrows, reserves);
if (util <= kink) {
return ((util * multiplierPerBlock) / BASE) + baseRatePerBlock;
} else {
uint normalRate = ((kink * multiplierPerBlock) / BASE) + baseRatePerBlock;
uint excessUtil = util - kink;
return ((excessUtil * jumpMultiplierPerBlock) / BASE) + normalRate;
}
}
/**
* @notice Calculates the current supply rate per block
* @param cash The amount of cash in the market
* @param borrows The amount of borrows in the market
* @param reserves The amount of reserves in the market
* @param reserveFactorMantissa The current reserve factor for the market
* @return The supply rate percentage per block as a mantissa (scaled by BASE)
*/
function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) virtual override public view returns (uint) {
uint oneMinusReserveFactor = BASE - reserveFactorMantissa;
uint borrowRate = getBorrowRateInternal(cash, borrows, reserves);
uint rateToPool = borrowRate * oneMinusReserveFactor / BASE;
return utilizationRate(cash, borrows, reserves) * rateToPool / BASE;
}
/**
* @notice Internal function to update the parameters of the interest rate model
* @param baseRatePerYear The approximate target base APR, as a mantissa (scaled by BASE)
* @param multiplierPerYear The rate of increase in interest rate wrt utilization (scaled by BASE)
* @param jumpMultiplierPerYear The multiplierPerBlock after hitting a specified utilization point
* @param kink_ The utilization point at which the jump multiplier is applied
*/
function updateJumpRateModelInternal(uint baseRatePerYear, uint multiplierPerYear, uint jumpMultiplierPerYear, uint kink_) internal {
baseRatePerBlock = baseRatePerYear / blocksPerYear;
multiplierPerBlock = (multiplierPerYear * BASE) / (blocksPerYear * kink_);
jumpMultiplierPerBlock = jumpMultiplierPerYear / blocksPerYear;
kink = kink_;
emit NewInterestParams(baseRatePerBlock, multiplierPerBlock, jumpMultiplierPerBlock, kink);
}
}
================================================
FILE: protocols/compound-v2/src/CDaiDelegate.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./CErc20Delegate.sol";
/**
* @title Compound's CDai Contract
* @notice CToken which wraps Multi-Collateral DAI
* @author Compound
*/
contract CDaiDelegate is CErc20Delegate {
/**
* @notice DAI adapter address
*/
address public daiJoinAddress;
/**
* @notice DAI Savings Rate (DSR) pot address
*/
address public potAddress;
/**
* @notice DAI vat address
*/
address public vatAddress;
/**
* @notice Delegate interface to become the implementation
* @param data The encoded arguments for becoming
*/
function _becomeImplementation(bytes memory data) override public {
require(msg.sender == admin, "only the admin may initialize the implementation");
(address daiJoinAddress_, address potAddress_) = abi.decode(data, (address, address));
return _becomeImplementation(daiJoinAddress_, potAddress_);
}
/**
* @notice Explicit interface to become the implementation
* @param daiJoinAddress_ DAI adapter address
* @param potAddress_ DAI Savings Rate (DSR) pot address
*/
function _becomeImplementation(address daiJoinAddress_, address potAddress_) internal {
// Get dai and vat and sanity check the underlying
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress_);
PotLike pot = PotLike(potAddress_);
GemLike dai = daiJoin.dai();
VatLike vat = daiJoin.vat();
require(address(dai) == underlying, "DAI must be the same as underlying");
// Remember the relevant addresses
daiJoinAddress = daiJoinAddress_;
potAddress = potAddress_;
vatAddress = address(vat);
// Approve moving our DAI into the vat through daiJoin
dai.approve(daiJoinAddress, type(uint).max);
// Approve the pot to transfer our funds within the vat
vat.hope(potAddress);
vat.hope(daiJoinAddress);
// Accumulate DSR interest -- must do this in order to doTransferIn
pot.drip();
// Transfer all cash in (doTransferIn does this regardless of amount)
doTransferIn(address(this), 0);
}
/**
* @notice Delegate interface to resign the implementation
*/
function _resignImplementation() override public {
require(msg.sender == admin, "only the admin may abandon the implementation");
// Transfer all cash out of the DSR - note that this relies on self-transfer
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);
PotLike pot = PotLike(potAddress);
VatLike vat = VatLike(vatAddress);
// Accumulate interest
pot.drip();
// Calculate the total amount in the pot, and move it out
uint pie = pot.pie(address(this));
pot.exit(pie);
// Checks the actual balance of DAI in the vat after the pot exit
uint bal = vat.dai(address(this));
// Remove our whole balance
daiJoin.exit(address(this), bal / RAY);
}
/*** CToken Overrides ***/
/**
* @notice Accrues DSR then applies accrued interest to total borrows and reserves
* @dev This calculates interest accrued from the last checkpointed block
* up to the current block and writes new checkpoint to storage.
*/
function accrueInterest() override public returns (uint) {
// Accumulate DSR interest
PotLike(potAddress).drip();
// Accumulate CToken interest
return super.accrueInterest();
}
/*** Safe Token ***/
/**
* @notice Gets balance of this contract in terms of the underlying
* @dev This excludes the value of the current message, if any
* @return The quantity of underlying tokens owned by this contract
*/
function getCashPrior() override internal view returns (uint) {
PotLike pot = PotLike(potAddress);
uint pie = pot.pie(address(this));
return mul(pot.chi(), pie) / RAY;
}
/**
* @notice Transfer the underlying to this contract and sweep into DSR pot
* @param from Address to transfer funds from
* @param amount Amount of underlying to transfer
* @return The actual amount that is transferred
*/
function doTransferIn(address from, uint amount) override internal returns (uint) {
// Read from storage once
address underlying_ = underlying;
// Perform the EIP-20 transfer in
EIP20Interface token = EIP20Interface(underlying_);
require(token.transferFrom(from, address(this), amount), "unexpected EIP-20 transfer in return");
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);
GemLike dai = GemLike(underlying_);
PotLike pot = PotLike(potAddress);
VatLike vat = VatLike(vatAddress);
// Convert all our DAI to internal DAI in the vat
daiJoin.join(address(this), dai.balanceOf(address(this)));
// Checks the actual balance of DAI in the vat after the join
uint bal = vat.dai(address(this));
// Calculate the percentage increase to th pot for the entire vat, and move it in
// Note: We may leave a tiny bit of DAI in the vat...but we do the whole thing every time
uint pie = bal / pot.chi();
pot.join(pie);
return amount;
}
/**
* @notice Transfer the underlying from this contract, after sweeping out of DSR pot
* @param to Address to transfer funds to
* @param amount Amount of underlying to transfer
*/
function doTransferOut(address payable to, uint amount) override internal {
DaiJoinLike daiJoin = DaiJoinLike(daiJoinAddress);
PotLike pot = PotLike(potAddress);
// Calculate the percentage decrease from the pot, and move that much out
// Note: Use a slightly larger pie size to ensure that we get at least amount in the vat
uint pie = add(mul(amount, RAY) / pot.chi(), 1);
pot.exit(pie);
daiJoin.exit(to, amount);
}
/*** Maker Internals ***/
uint256 constant RAY = 10 ** 27;
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, "add-overflow");
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, "mul-overflow");
}
}
/*** Maker Interfaces ***/
interface PotLike {
function chi() external view returns (uint);
function pie(address) external view returns (uint);
function drip() external returns (uint);
function join(uint) external;
function exit(uint) external;
}
interface GemLike {
function approve(address, uint) external;
function balanceOf(address) external view returns (uint);
function transferFrom(address, address, uint) external returns (bool);
}
interface VatLike {
function dai(address) external view returns (uint);
function hope(address) external;
}
interface DaiJoinLike {
function vat() external returns (VatLike);
function dai() external returns (GemLike);
function join(address, uint) external payable;
function exit(address, uint) external;
}
================================================
FILE: protocols/compound-v2/src/CErc20.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./CToken.sol";
interface CompLike {
function delegate(address delegatee) external;
}
/**
* @title Compound's CErc20 Contract
* @notice CTokens which wrap an EIP-20 underlying
* @author Compound
*/
contract CErc20 is CToken, CErc20Interface {
/**
* @notice Initialize the new money market
* @param underlying_ The address of the underlying asset
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
* @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
* @param name_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
*/
function initialize(address underlying_,
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_) public {
// CToken initialize does the bulk of the work
super.initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);
// Set underlying and sanity check it
underlying = underlying_;
EIP20Interface(underlying).totalSupply();
}
/*** User Interface ***/
/**
* @notice Sender supplies assets into the market and receives cTokens in exchange
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param mintAmount The amount of the underlying asset to supply
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function mint(uint mintAmount) override external returns (uint) {
mintInternal(mintAmount);
return NO_ERROR;
}
/**
* @notice Sender redeems cTokens in exchange for the underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemTokens The number of cTokens to redeem into underlying
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeem(uint redeemTokens) override external returns (uint) {
redeemInternal(redeemTokens);
return NO_ERROR;
}
/**
* @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemAmount The amount of underlying to redeem
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlying(uint redeemAmount) override external returns (uint) {
redeemUnderlyingInternal(redeemAmount);
return NO_ERROR;
}
/**
* @notice Sender borrows assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrow(uint borrowAmount) override external returns (uint) {
borrowInternal(borrowAmount);
return NO_ERROR;
}
/**
* @notice Sender repays their own borrow
* @param repayAmount The amount to repay, or -1 for the full outstanding amount
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrow(uint repayAmount) override external returns (uint) {
repayBorrowInternal(repayAmount);
return NO_ERROR;
}
/**
* @notice Sender repays a borrow belonging to borrower
* @param borrower the account with the debt being payed off
* @param repayAmount The amount to repay, or -1 for the full outstanding amount
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrowBehalf(address borrower, uint repayAmount) override external returns (uint) {
repayBorrowBehalfInternal(borrower, repayAmount);
return NO_ERROR;
}
/**
* @notice The sender liquidates the borrowers collateral.
* The collateral seized is transferred to the liquidator.
* @param borrower The borrower of this cToken to be liquidated
* @param repayAmount The amount of the underlying borrowed asset to repay
* @param cTokenCollateral The market in which to seize collateral from the borrower
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) override external returns (uint) {
liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral);
return NO_ERROR;
}
/**
* @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)
* @param token The address of the ERC-20 token to sweep
*/
function sweepToken(EIP20NonStandardInterface token) override external {
require(msg.sender == admin, "CErc20::sweepToken: only admin can sweep tokens");
require(address(token) != underlying, "CErc20::sweepToken: can not sweep underlying token");
uint256 balance = token.balanceOf(address(this));
token.transfer(admin, balance);
}
/**
* @notice The sender adds to reserves.
* @param addAmount The amount fo underlying token to add as reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _addReserves(uint addAmount) override external returns (uint) {
return _addReservesInternal(addAmount);
}
/*** Safe Token ***/
/**
* @notice Gets balance of this contract in terms of the underlying
* @dev This excludes the value of the current message, if any
* @return The quantity of underlying tokens owned by this contract
*/
function getCashPrior() virtual override internal view returns (uint) {
EIP20Interface token = EIP20Interface(underlying);
return token.balanceOf(address(this));
}
// test Helper
function getCashPriorpub() public view returns(uint) {
EIP20Interface token = EIP20Interface(underlying);
return token.balanceOf(address(this));
}
/**
* @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case.
* This will revert due to insufficient balance or insufficient allowance.
* This function returns the actual amount received,
* which may be less than `amount` if there is a fee attached to the transfer.
*
* Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
* See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
function doTransferIn(address from, uint amount) virtual override internal returns (uint) {
// Read from storage once
address underlying_ = underlying;
EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying_);
uint balanceBefore = EIP20Interface(underlying_).balanceOf(address(this));
token.transferFrom(from, address(this), amount);
bool success;
assembly {
switch returndatasize()
case 0 { // This is a non-standard ERC-20
success := not(0) // set success to true
}
case 32 { // This is a compliant ERC-20
returndatacopy(0, 0, 32)
success := mload(0) // Set `success = returndata` of override external call
}
default { // This is an excessively non-compliant ERC-20, revert.
revert(0, 0)
}
}
require(success, "TOKEN_TRANSFER_IN_FAILED");
// Calculate the amount that was *actually* transferred
uint balanceAfter = EIP20Interface(underlying_).balanceOf(address(this));
return balanceAfter - balanceBefore; // underflow already checked above, just subtract
}
/**
* @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory
* error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to
* insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified
* it is >= amount, this should not revert in normal conditions.
*
* Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
* See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
function doTransferOut(address payable to, uint amount) virtual override internal {
EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
token.transfer(to, amount);
bool success;
assembly {
switch returndatasize()
case 0 { // This is a non-standard ERC-20
success := not(0) // set success to true
}
case 32 { // This is a compliant ERC-20
returndatacopy(0, 0, 32)
success := mload(0) // Set `success = returndata` of override external call
}
default { // This is an excessively non-compliant ERC-20, revert.
revert(0, 0)
}
}
require(success, "TOKEN_TRANSFER_OUT_FAILED");
}
/**
* @notice Admin call to delegate the votes of the COMP-like underlying
* @param compLikeDelegatee The address to delegate votes to
* @dev CTokens whose underlying are not CompLike should revert here
*/
function _delegateCompLikeTo(address compLikeDelegatee) external {
require(msg.sender == admin, "only the admin may set the comp-like delegate");
CompLike(underlying).delegate(compLikeDelegatee);
}
}
================================================
FILE: protocols/compound-v2/src/CErc20Delegate.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./CErc20.sol";
/**
* @title Compound's CErc20Delegate Contract
* @notice CTokens which wrap an EIP-20 underlying and are delegated to
* @author Compound
*/
contract CErc20Delegate is CErc20, CDelegateInterface {
/**
* @notice Construct an empty delegate
*/
constructor() {}
/**
* @notice Called by the delegator on a delegate to initialize it for duty
* @param data The encoded bytes data for any initialization
*/
function _becomeImplementation(bytes memory data) virtual override public {
// Shh -- currently unused
data;
// Shh -- we don't ever want this hook to be marked pure
if (false) {
implementation = address(0);
}
require(msg.sender == admin, "only the admin may call _becomeImplementation");
}
/**
* @notice Called by the delegator on a delegate to forfeit its responsibility
*/
function _resignImplementation() virtual override public {
// Shh -- we don't ever want this hook to be marked pure
if (false) {
implementation = address(0);
}
require(msg.sender == admin, "only the admin may call _resignImplementation");
}
}
================================================
FILE: protocols/compound-v2/src/CErc20Delegator.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./CTokenInterfaces.sol";
/**
* @title Compound's CErc20Delegator Contract
* @notice CTokens which wrap an EIP-20 underlying and delegate to an implementation
* @author Compound
*/
contract CErc20Delegator is CTokenInterface, CErc20Interface, CDelegatorInterface {
/**
* @notice Construct a new money market
* @param underlying_ The address of the underlying asset
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
* @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
* @param name_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
* @param admin_ Address of the administrator of this token
* @param implementation_ The address of the implementation the contract delegates to
* @param becomeImplementationData The encoded args for becomeImplementation
*/
constructor(address underlying_,
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_,
address payable admin_,
address implementation_,
bytes memory becomeImplementationData) {
// Creator of the contract is admin during initialization
admin = payable(msg.sender);
// First delegate gets to initialize the delegator (i.e. storage contract)
delegateTo(implementation_, abi.encodeWithSignature("initialize(address,address,address,uint256,string,string,uint8)",
underlying_,
comptroller_,
interestRateModel_,
initialExchangeRateMantissa_,
name_,
symbol_,
decimals_));
// New implementations always get set via the settor (post-initialize)
_setImplementation(implementation_, false, becomeImplementationData);
// Set the proper admin now that initialization is done
admin = admin_;
}
/**
* @notice Called by the admin to update the implementation of the delegator
* @param implementation_ The address of the new implementation for delegation
* @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
* @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
*/
function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData)override public {
require(msg.sender == admin, "CErc20Delegator::_setImplementation: Caller must be admin");
if (allowResign) {
delegateToImplementation(abi.encodeWithSignature("_resignImplementation()"));
}
address oldImplementation = implementation;
implementation = implementation_;
delegateToImplementation(abi.encodeWithSignature("_becomeImplementation(bytes)", becomeImplementationData));
emit NewImplementation(oldImplementation, implementation);
}
/**
* @notice Sender supplies assets into the market and receives cTokens in exchange
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param mintAmount The amount of the underlying asset to supply
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function mint(uint mintAmount) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("mint(uint256)", mintAmount));
return abi.decode(data, (uint));
}
/**
* @notice Sender redeems cTokens in exchange for the underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemTokens The number of cTokens to redeem into underlying
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeem(uint redeemTokens) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("redeem(uint256)", redeemTokens));
return abi.decode(data, (uint));
}
/**
* @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemAmount The amount of underlying to redeem
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlying(uint redeemAmount) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("redeemUnderlying(uint256)", redeemAmount));
return abi.decode(data, (uint));
}
/**
* @notice Sender borrows assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrow(uint borrowAmount) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("borrow(uint256)", borrowAmount));
return abi.decode(data, (uint));
}
/**
* @notice Sender repays their own borrow
* @param repayAmount The amount to repay, or -1 for the full outstanding amount
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrow(uint repayAmount) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("repayBorrow(uint256)", repayAmount));
return abi.decode(data, (uint));
}
/**
* @notice Sender repays a borrow belonging to borrower
* @param borrower the account with the debt being payed off
* @param repayAmount The amount to repay, or -1 for the full outstanding amount
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrowBehalf(address borrower, uint repayAmount) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("repayBorrowBehalf(address,uint256)", borrower, repayAmount));
return abi.decode(data, (uint));
}
/**
* @notice The sender liquidates the borrowers collateral.
* The collateral seized is transferred to the liquidator.
* @param borrower The borrower of this cToken to be liquidated
* @param cTokenCollateral The market in which to seize collateral from the borrower
* @param repayAmount The amount of the underlying borrowed asset to repay
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("liquidateBorrow(address,uint256,address)", borrower, repayAmount, cTokenCollateral));
return abi.decode(data, (uint));
}
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(address dst, uint amount) override external returns (bool) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("transfer(address,uint256)", dst, amount));
return abi.decode(data, (bool));
}
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(address src, address dst, uint256 amount) override external returns (bool) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("transferFrom(address,address,uint256)", src, dst, amount));
return abi.decode(data, (bool));
}
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) override external returns (bool) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("approve(address,uint256)", spender, amount));
return abi.decode(data, (bool));
}
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(address owner, address spender) override external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("allowance(address,address)", owner, spender));
return abi.decode(data, (uint));
}
/**
* @notice Get the token balance of the `owner`
* @param owner The address of the account to query
* @return The number of tokens owned by `owner`
*/
function balanceOf(address owner) override external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("balanceOf(address)", owner));
return abi.decode(data, (uint));
}
/**
* @notice Get the underlying balance of the `owner`
* @dev This also accrues interest in a transaction
* @param owner The address of the account to query
* @return The amount of underlying owned by `owner`
*/
function balanceOfUnderlying(address owner) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("balanceOfUnderlying(address)", owner));
return abi.decode(data, (uint));
}
/**
* @notice Get a snapshot of the account's balances, and the cached exchange rate
* @dev This is used by comptroller to more efficiently perform liquidity checks.
* @param account Address of the account to snapshot
* @return (possible error, token balance, borrow balance, exchange rate mantissa)
*/
function getAccountSnapshot(address account) override external view returns (uint, uint, uint, uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("getAccountSnapshot(address)", account));
return abi.decode(data, (uint, uint, uint, uint));
}
/**
* @notice Returns the current per-block borrow interest rate for this cToken
* @return The borrow interest rate per block, scaled by 1e18
*/
function borrowRatePerBlock() override external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("borrowRatePerBlock()"));
return abi.decode(data, (uint));
}
/**
* @notice Returns the current per-block supply interest rate for this cToken
* @return The supply interest rate per block, scaled by 1e18
*/
function supplyRatePerBlock() override external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("supplyRatePerBlock()"));
return abi.decode(data, (uint));
}
/**
* @notice Returns the current total borrows plus accrued interest
* @return The total borrows with interest
*/
function totalBorrowsCurrent() override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("totalBorrowsCurrent()"));
return abi.decode(data, (uint));
}
/**
* @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
* @param account The address whose balance should be calculated after updating borrowIndex
* @return The calculated balance
*/
function borrowBalanceCurrent(address account) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("borrowBalanceCurrent(address)", account));
return abi.decode(data, (uint));
}
/**
* @notice Return the borrow balance of account based on stored data
* @param account The address whose balance should be calculated
* @return The calculated balance
*/
function borrowBalanceStored(address account) override public view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("borrowBalanceStored(address)", account));
return abi.decode(data, (uint));
}
/**
* @notice Accrue interest then return the up-to-date exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateCurrent() override public returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("exchangeRateCurrent()"));
return abi.decode(data, (uint));
}
/**
* @notice Calculates the exchange rate from the underlying to the CToken
* @dev This function does not accrue interest before calculating the exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateStored() override public view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("exchangeRateStored()"));
return abi.decode(data, (uint));
}
/**
* @notice Get cash balance of this cToken in the underlying asset
* @return The quantity of underlying asset owned by this contract
*/
function getCash() override external view returns (uint) {
bytes memory data = delegateToViewImplementation(abi.encodeWithSignature("getCash()"));
return abi.decode(data, (uint));
}
/**
* @notice Applies accrued interest to total borrows and reserves.
* @dev This calculates interest accrued from the last checkpointed block
* up to the current block and writes new checkpoint to storage.
*/
function accrueInterest() override public returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("accrueInterest()"));
return abi.decode(data, (uint));
}
/**
* @notice Transfers collateral tokens (this market) to the liquidator.
* @dev Will fail unless called by another cToken during the process of liquidation.
* Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.
* @param liquidator The account receiving seized collateral
* @param borrower The account having collateral seized
* @param seizeTokens The number of cTokens to seize
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function seize(address liquidator, address borrower, uint seizeTokens) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("seize(address,address,uint256)", liquidator, borrower, seizeTokens));
return abi.decode(data, (uint));
}
/**
* @notice A public function to sweep accidental ERC-20 transfers to this contract. Tokens are sent to admin (timelock)
* @param token The address of the ERC-20 token to sweep
*/
function sweepToken(EIP20NonStandardInterface token) override external {
delegateToImplementation(abi.encodeWithSignature("sweepToken(address)", token));
}
/*** Admin Functions ***/
/**
* @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
* @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
* @param newPendingAdmin New pending admin.
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setPendingAdmin(address payable newPendingAdmin) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setPendingAdmin(address)", newPendingAdmin));
return abi.decode(data, (uint));
}
/**
* @notice Sets a new comptroller for the market
* @dev Admin function to set a new comptroller
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setComptroller(ComptrollerInterface newComptroller) override public returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setComptroller(address)", newComptroller));
return abi.decode(data, (uint));
}
/**
* @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
* @dev Admin function to accrue interest and set a new reserve factor
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setReserveFactor(uint newReserveFactorMantissa) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setReserveFactor(uint256)", newReserveFactorMantissa));
return abi.decode(data, (uint));
}
/**
* @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
* @dev Admin function for pending admin to accept role and update admin
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _acceptAdmin() override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_acceptAdmin()"));
return abi.decode(data, (uint));
}
/**
* @notice Accrues interest and adds reserves by transferring from admin
* @param addAmount Amount of reserves to add
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _addReserves(uint addAmount) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_addReserves(uint256)", addAmount));
return abi.decode(data, (uint));
}
/**
* @notice Accrues interest and reduces reserves by transferring to admin
* @param reduceAmount Amount of reduction to reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _reduceReserves(uint reduceAmount) override external returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_reduceReserves(uint256)", reduceAmount));
return abi.decode(data, (uint));
}
/**
* @notice Accrues interest and updates the interest rate model using _setInterestRateModelFresh
* @dev Admin function to accrue interest and update the interest rate model
* @param newInterestRateModel the new interest rate model to use
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setInterestRateModel(InterestRateModel newInterestRateModel) override public returns (uint) {
bytes memory data = delegateToImplementation(abi.encodeWithSignature("_setInterestRateModel(address)", newInterestRateModel));
return abi.decode(data, (uint));
}
/**
* @notice Internal method to delegate execution to another contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* @param callee The contract to delegatecall
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateTo(address callee, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returnData) = callee.delegatecall(data);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize())
}
}
return returnData;
}
/**
* @notice Delegates execution to the implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateToImplementation(bytes memory data) public returns (bytes memory) {
return delegateTo(implementation, data);
}
/**
* @notice Delegates execution to an implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateToViewImplementation(bytes memory data) public view returns (bytes memory) {
(bool success, bytes memory returnData) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", data));
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize())
}
}
return abi.decode(returnData, (bytes));
}
/**
* @notice Delegates execution to an implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
*/
fallback() external payable {
require(msg.value == 0,"CErc20Delegator:fallback: cannot send value to fallback");
// delegate all other functions to current implementation
(bool success, ) = implementation.delegatecall(msg.data);
assembly {
let free_mem_ptr := mload(0x40)
returndatacopy(free_mem_ptr, 0, returndatasize())
switch success
case 0 { revert(free_mem_ptr, returndatasize()) }
default { return(free_mem_ptr, returndatasize()) }
}
}
}
================================================
FILE: protocols/compound-v2/src/CErc20Immutable.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./CErc20.sol";
/**
* @title Compound's CErc20Immutable Contract
* @notice CTokens which wrap an EIP-20 underlying and are immutable
* @author Compound
*/
contract CErc20Immutable is CErc20 {
/**
* @notice Construct a new money market
* @param underlying_ The address of the underlying asset
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
* @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
* @param name_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
* @param admin_ Address of the administrator of this token
*/
constructor(address underlying_,
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_,
address payable admin_) {
// Creator of the contract is admin during initialization
admin = payable(msg.sender);
// Initialize the market
initialize(underlying_, comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);
// Set the proper admin now that initialization is done
admin = admin_;
}
}
================================================
FILE: protocols/compound-v2/src/CEther.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./CToken.sol";
/**
* @title Compound's CEther Contract
* @notice CToken which wraps Ether
* @author Compound
*/
contract CEther is CToken {
/**
* @notice Construct a new CEther money market
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
* @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
* @param name_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
* @param admin_ Address of the administrator of this token
*/
constructor(ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_,
address payable admin_) {
// Creator of the contract is admin during initialization
admin = payable(msg.sender);
initialize(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_);
// Set the proper admin now that initialization is done
admin = admin_;
}
/*** User Interface ***/
/**
* @notice Sender supplies assets into the market and receives cTokens in exchange
* @dev Reverts upon any failure
*/
function mint() external payable {
mintInternal(msg.value);
}
/**
* @notice Sender redeems cTokens in exchange for the underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemTokens The number of cTokens to redeem into underlying
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeem(uint redeemTokens) external returns (uint) {
redeemInternal(redeemTokens);
return NO_ERROR;
}
/**
* @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemAmount The amount of underlying to redeem
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlying(uint redeemAmount) external returns (uint) {
redeemUnderlyingInternal(redeemAmount);
return NO_ERROR;
}
/**
* @notice Sender borrows assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrow(uint borrowAmount) external returns (uint) {
borrowInternal(borrowAmount);
return NO_ERROR;
}
/**
* @notice Sender repays their own borrow
* @dev Reverts upon any failure
*/
function repayBorrow() external payable {
repayBorrowInternal(msg.value);
}
/**
* @notice Sender repays a borrow belonging to borrower
* @dev Reverts upon any failure
* @param borrower the account with the debt being payed off
*/
function repayBorrowBehalf(address borrower) external payable {
repayBorrowBehalfInternal(borrower, msg.value);
}
/**
* @notice The sender liquidates the borrowers collateral.
* The collateral seized is transferred to the liquidator.
* @dev Reverts upon any failure
* @param borrower The borrower of this cToken to be liquidated
* @param cTokenCollateral The market in which to seize collateral from the borrower
*/
function liquidateBorrow(address borrower, CToken cTokenCollateral) external payable {
liquidateBorrowInternal(borrower, msg.value, cTokenCollateral);
}
/**
* @notice The sender adds to reserves.
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _addReserves() external payable returns (uint) {
return _addReservesInternal(msg.value);
}
/**
* @notice Send Ether to CEther to mint
*/
receive() external payable {
mintInternal(msg.value);
}
/*** Safe Token ***/
/**
* @notice Gets balance of this contract in terms of Ether, before this message
* @dev This excludes the value of the current message, if any
* @return The quantity of Ether owned by this contract
*/
function getCashPrior() override internal view returns (uint) {
return address(this).balance - msg.value;
}
/**
* @notice Perform the actual transfer in, which is a no-op
* @param from Address sending the Ether
* @param amount Amount of Ether being sent
* @return The actual amount of Ether transferred
*/
function doTransferIn(address from, uint amount) override internal returns (uint) {
// Sanity checks
require(msg.sender == from, "sender mismatch");
require(msg.value == amount, "value mismatch");
return amount;
}
function doTransferOut(address payable to, uint amount) virtual override internal {
/* Send the Ether, with minimal gas and revert on failure */
to.transfer(amount);
}
}
================================================
FILE: protocols/compound-v2/src/CToken.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./ComptrollerInterface.sol";
import "./CTokenInterfaces.sol";
import "./ErrorReporter.sol";
import "./EIP20Interface.sol";
import "./InterestRateModel.sol";
import "./ExponentialNoError.sol";
/**
* @title Compound's CToken Contract
* @notice Abstract base for CTokens
* @author Compound
*/
abstract contract CToken is CTokenInterface, ExponentialNoError, TokenErrorReporter {
/**
* @notice Initialize the money market
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
* @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
* @param name_ EIP-20 name of this token
* @param symbol_ EIP-20 symbol of this token
* @param decimals_ EIP-20 decimal precision of this token
*/
function initialize(ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_) public {
admin = payable(address(msg.sender));
require(msg.sender == admin, "only admin may initialize the market");
require(accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once");
// Set initial exchange rate
initialExchangeRateMantissa = initialExchangeRateMantissa_;
require(initialExchangeRateMantissa > 0, "initial exchange rate must be greater than zero.");
// Set the comptroller
uint err = _setComptroller(comptroller_);
require(err == NO_ERROR, "setting comptroller failed");
// Initialize block number and borrow index (block number mocks depend on comptroller being set)
accrualBlockNumber = getBlockNumber();
borrowIndex = mantissaOne;
// Set the interest rate model (depends on block number / borrow index)
err = _setInterestRateModelFresh(interestRateModel_);
require(err == NO_ERROR, "setting interest rate model failed");
name = name_;
symbol = symbol_;
decimals = decimals_;
// The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)
_notEntered = true;
}
/**
* @notice Transfer `tokens` tokens from `src` to `dst` by `spender`
* @dev Called by both `transfer` and `transferFrom` internally
* @param spender The address of the account performing the transfer
* @param src The address of the source account
* @param dst The address of the destination account
* @param tokens The number of tokens to transfer
* @return 0 if the transfer succeeded, else revert
*/
function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) {
/* Fail if transfer not allowed */
uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens);
if (allowed != 0) {
revert TransferComptrollerRejection(allowed);
}
/* Do not allow self-transfers */
if (src == dst) {
revert TransferNotAllowed();
}
/* Get the allowance, infinite for the account owner */
uint startingAllowance = 0;
if (spender == src) {
startingAllowance = type(uint).max;
} else {
startingAllowance = transferAllowances[src][spender];
}
/* Do the calculations, checking for {under,over}flow */
uint allowanceNew = startingAllowance - tokens;
uint srcTokensNew = accountTokens[src] - tokens;
uint dstTokensNew = accountTokens[dst] + tokens;
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
accountTokens[src] = srcTokensNew;
accountTokens[dst] = dstTokensNew;
/* Eat some of the allowance (if necessary) */
if (startingAllowance != type(uint).max) {
transferAllowances[src][spender] = allowanceNew;
}
/* We emit a Transfer event */
emit Transfer(src, dst, tokens);
// unused function
// comptroller.transferVerify(address(this), src, dst, tokens);
return NO_ERROR;
}
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(address dst, uint256 amount) override external nonReentrant returns (bool) {
return transferTokens(msg.sender, msg.sender, dst, amount) == NO_ERROR;
}
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(address src, address dst, uint256 amount) override external nonReentrant returns (bool) {
return transferTokens(msg.sender, src, dst, amount) == NO_ERROR;
}
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (uint256.max means infinite)
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) override external returns (bool) {
address src = msg.sender;
transferAllowances[src][spender] = amount;
emit Approval(src, spender, amount);
return true;
}
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(address owner, address spender) override external view returns (uint256) {
return transferAllowances[owner][spender];
}
/**
* @notice Get the token balance of the `owner`
* @param owner The address of the account to query
* @return The number of tokens owned by `owner`
*/
function balanceOf(address owner) override external view returns (uint256) {
return accountTokens[owner];
}
/**
* @notice Get the underlying balance of the `owner`
* @dev This also accrues interest in a transaction
* @param owner The address of the account to query
* @return The amount of underlying owned by `owner`
*/
function balanceOfUnderlying(address owner) override external returns (uint) {
Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});
return mul_ScalarTruncate(exchangeRate, accountTokens[owner]);
}
/**
* @notice Get a snapshot of the account's balances, and the cached exchange rate
* @dev This is used by comptroller to more efficiently perform liquidity checks.
* @param account Address of the account to snapshot
* @return (possible error, token balance, borrow balance, exchange rate mantissa)
*/
function getAccountSnapshot(address account) override external view returns (uint, uint, uint, uint) {
return (
NO_ERROR,
accountTokens[account],
borrowBalanceStoredInternal(account),
exchangeRateStoredInternal()
);
}
/**
* @dev Function to simply retrieve block number
* This exists mainly for inheriting test contracts to stub this result.
*/
function getBlockNumber() virtual internal view returns (uint) {
return block.number;
}
/**
* @notice Returns the current per-block borrow interest rate for this cToken
* @return The borrow interest rate per block, scaled by 1e18
*/
function borrowRatePerBlock() override external view returns (uint) {
return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves);
}
/**
* @notice Returns the current per-block supply interest rate for this cToken
* @return The supply interest rate per block, scaled by 1e18
*/
function supplyRatePerBlock() override external view returns (uint) {
return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa);
}
/**
* @notice Returns the current total borrows plus accrued interest
* @return The total borrows with interest
*/
function totalBorrowsCurrent() override external nonReentrant returns (uint) {
accrueInterest();
return totalBorrows;
}
/**
* @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
* @param account The address whose balance should be calculated after updating borrowIndex
* @return The calculated balance
*/
function borrowBalanceCurrent(address account) override external nonReentrant returns (uint) {
accrueInterest();
return borrowBalanceStored(account);
}
/**
* @notice Return the borrow balance of account based on stored data
* @param account The address whose balance should be calculated
* @return The calculated balance
*/
function borrowBalanceStored(address account) override public view returns (uint) {
return borrowBalanceStoredInternal(account);
}
/**
* @notice Return the borrow balance of account based on stored data
* @param account The address whose balance should be calculated
* @return (error code, the calculated balance or 0 if error code is non-zero)
*/
function borrowBalanceStoredInternal(address account) internal view returns (uint) {
/* Get borrowBalance and borrowIndex */
BorrowSnapshot storage borrowSnapshot = accountBorrows[account];
/* If borrowBalance = 0 then borrowIndex is likely also 0.
* Rather than failing the calculation with a division by 0, we immediately return 0 in this case.
*/
if (borrowSnapshot.principal == 0) {
return 0;
}
/* Calculate new borrow balance using the interest index:
* recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex
*/
uint principalTimesIndex = borrowSnapshot.principal * borrowIndex;
return principalTimesIndex / borrowSnapshot.interestIndex;
}
/**
* @notice Accrue interest then return the up-to-date exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateCurrent() override public nonReentrant returns (uint) {
accrueInterest();
return exchangeRateStored();
}
/**
* @notice Calculates the exchange rate from the underlying to the CToken
* @dev This function does not accrue interest before calculating the exchange rate
* @return Calculated exchange rate scaled by 1e18
*/
function exchangeRateStored() override public view returns (uint) {
return exchangeRateStoredInternal();
}
/**
* @notice Calculates the exchange rate from the underlying to the CToken
* @dev This function does not accrue interest before calculating the exchange rate
* @return calculated exchange rate scaled by 1e18
*/
function exchangeRateStoredInternal() virtual internal view returns (uint) {
uint _totalSupply = totalSupply;
if (_totalSupply == 0) {
/*
* If there are no tokens minted:
* exchangeRate = initialExchangeRate
*/
return initialExchangeRateMantissa;
} else {
/*
* Otherwise:
* exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
*/
uint totalCash = getCashPrior();
uint cashPlusBorrowsMinusReserves = totalCash + totalBorrows - totalReserves;
uint exchangeRate = cashPlusBorrowsMinusReserves * expScale / _totalSupply;
return exchangeRate;
}
}
/**
* @notice Get cash balance of this cToken in the underlying asset
* @return The quantity of underlying asset owned by this contract
*/
function getCash() override external view returns (uint) {
return getCashPrior();
}
/**
* @notice Applies accrued interest to total borrows and reserves
* @dev This calculates interest accrued from the last checkpointed block
* up to the current block and writes new checkpoint to storage.
*/
function accrueInterest() virtual override public returns (uint) {
/* Remember the initial block number */
uint currentBlockNumber = getBlockNumber();
uint accrualBlockNumberPrior = accrualBlockNumber;
/* Short-circuit accumulating 0 interest */
if (accrualBlockNumberPrior == currentBlockNumber) {
return NO_ERROR;
}
/* Read the previous values out of storage */
uint cashPrior = getCashPrior();
uint borrowsPrior = totalBorrows;
uint reservesPrior = totalReserves;
uint borrowIndexPrior = borrowIndex;
/* Calculate the current borrow interest rate */
uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);
require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high");
/* Calculate the number of blocks elapsed since the last accrual */
uint blockDelta = currentBlockNumber - accrualBlockNumberPrior;
/*
* Calculate the interest accumulated into borrows and reserves and the new index:
* simpleInterestFactor = borrowRate * blockDelta
* interestAccumulated = simpleInterestFactor * totalBorrows
* totalBorrowsNew = interestAccumulated + totalBorrows
* totalReservesNew = interestAccumulated * reserveFactor + totalReserves
* borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex
*/
Exp memory simpleInterestFactor = mul_(Exp({mantissa: borrowRateMantissa}), blockDelta);
uint interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior);
uint totalBorrowsNew = interestAccumulated + borrowsPrior;
uint totalReservesNew = mul_ScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);
uint borrowIndexNew = mul_ScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/* We write the previously calculated values into storage */
accrualBlockNumber = currentBlockNumber;
borrowIndex = borrowIndexNew;
totalBorrows = totalBorrowsNew;
totalReserves = totalReservesNew;
/* We emit an AccrueInterest event */
emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);
return NO_ERROR;
}
/**
* @notice Sender supplies assets into the market and receives cTokens in exchange
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param mintAmount The amount of the underlying asset to supply
*/
function mintInternal(uint mintAmount) internal nonReentrant {
accrueInterest();
// mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to
mintFresh(msg.sender, mintAmount);
}
/**
* @notice User supplies assets into the market and receives cTokens in exchange
* @dev Assumes interest has already been accrued up to the current block
* @param minter The address of the account which is supplying the assets
* @param mintAmount The amount of the underlying asset to supply
*/
function mintFresh(address minter, uint mintAmount) internal {
/* Fail if mint not allowed */
uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);
if (allowed != 0) {
revert MintComptrollerRejection(allowed);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
revert MintFreshnessCheck();
}
Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()});
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We call `doTransferIn` for the minter and the mintAmount.
* Note: The cToken must handle variations between ERC-20 and ETH underlying.
* `doTransferIn` reverts if anything goes wrong, since we can't be sure if
* side-effects occurred. The function returns the amount actually transferred,
* in case of a fee. On success, the cToken holds an additional `actualMintAmount`
* of cash.
*/
uint actualMintAmount = doTransferIn(minter, mintAmount);
/*
* We get the current exchange rate and calculate the number of cTokens to be minted:
* mintTokens = actualMintAmount / exchangeRate
*/
uint mintTokens = div_(actualMintAmount, exchangeRate);
/*
* We calculate the new total supply of cTokens and minter token balance, checking for overflow:
* totalSupplyNew = totalSupply + mintTokens
* accountTokensNew = accountTokens[minter] + mintTokens
* And write them into storage
*/
totalSupply = totalSupply + mintTokens;
accountTokens[minter] = accountTokens[minter] + mintTokens;
/* We emit a Mint event, and a Transfer event */
emit Mint(minter, actualMintAmount, mintTokens);
emit Transfer(address(this), minter, mintTokens);
/* We call the defense hook */
// unused function
// comptroller.mintVerify(address(this), minter, actualMintAmount, mintTokens);
}
/**
* @notice Sender redeems cTokens in exchange for the underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemTokens The number of cTokens to redeem into underlying
*/
function redeemInternal(uint redeemTokens) internal nonReentrant {
accrueInterest();
// redeemFresh emits redeem-specific logs on errors, so we don't need to
redeemFresh(payable(msg.sender), redeemTokens, 0);
}
/**
* @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemAmount The amount of underlying to receive from redeeming cTokens
*/
function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant {
accrueInterest();
// redeemFresh emits redeem-specific logs on errors, so we don't need to
redeemFresh(payable(msg.sender), 0, redeemAmount);
}
/**
* @notice User redeems cTokens in exchange for the underlying asset
* @dev Assumes interest has already been accrued up to the current block
* @param redeemer The address of the account which is redeeming the tokens
* @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)
* @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)
*/
function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal {
require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero");
/* exchangeRate = invoke Exchange Rate Stored() */
Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal() });
uint redeemTokens;
uint redeemAmount;
/* If redeemTokensIn > 0: */
if (redeemTokensIn > 0) {
/*
* We calculate the exchange rate and the amount of underlying to be redeemed:
* redeemTokens = redeemTokensIn
* redeemAmount = redeemTokensIn x exchangeRateCurrent
*/
redeemTokens = redeemTokensIn;
redeemAmount = mul_ScalarTruncate(exchangeRate, redeemTokensIn);
} else {
/*
* We get the current exchange rate and calculate the amount to be redeemed:
* redeemTokens = redeemAmountIn / exchangeRate
* redeemAmount = redeemAmountIn
*/
redeemTokens = div_(redeemAmountIn, exchangeRate);
redeemAmount = redeemAmountIn;
}
/* Fail if redeem not allowed */
uint allowed = comptroller.redeemAllowed(address(this), redeemer, redeemTokens);
if (allowed != 0) {
revert RedeemComptrollerRejection(allowed);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
revert RedeemFreshnessCheck();
}
/* Fail gracefully if protocol has insufficient cash */
if (getCashPrior() < redeemAmount) {
revert RedeemTransferOutNotPossible();
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We write the previously calculated values into storage.
* Note: Avoid token reentrancy attacks by writing reduced supply before external transfer.
*/
totalSupply = totalSupply - redeemTokens;
accountTokens[redeemer] = accountTokens[redeemer] - redeemTokens;
/*
* We invoke doTransferOut for the redeemer and the redeemAmount.
* Note: The cToken must handle variations between ERC-20 and ETH underlying.
* On success, the cToken has redeemAmount less of cash.
* doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
*/
doTransferOut(redeemer, redeemAmount);
/* We emit a Transfer event, and a Redeem event */
emit Transfer(redeemer, address(this), redeemTokens);
emit Redeem(redeemer, redeemAmount, redeemTokens);
/* We call the defense hook */
comptroller.redeemVerify(address(this), redeemer, redeemAmount, redeemTokens);
}
/**
* @notice Sender borrows assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
*/
function borrowInternal(uint borrowAmount) internal nonReentrant {
accrueInterest();
// borrowFresh emits borrow-specific logs on errors, so we don't need to
borrowFresh(payable(msg.sender), borrowAmount);
}
/**
* @notice Users borrow assets from the protocol to their own address
* @param borrowAmount The amount of the underlying asset to borrow
*/
function borrowFresh(address payable borrower, uint borrowAmount) internal {
/* Fail if borrow not allowed */
uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount);
if (allowed != 0) {
revert BorrowComptrollerRejection(allowed);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
revert BorrowFreshnessCheck();
}
/* Fail gracefully if protocol has insufficient underlying cash */
if (getCashPrior() < borrowAmount) {
revert BorrowCashNotAvailable();
}
/*
* We calculate the new borrower and total borrow balances, failing on overflow:
* accountBorrowNew = accountBorrow + borrowAmount
* totalBorrowsNew = totalBorrows + borrowAmount
*/
uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower);
uint accountBorrowsNew = accountBorrowsPrev + borrowAmount;
uint totalBorrowsNew = totalBorrows + borrowAmount;
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We write the previously calculated values into storage.
* Note: Avoid token reentrancy attacks by writing increased borrow before external transfer.
`*/
accountBorrows[borrower].principal = accountBorrowsNew;
accountBorrows[borrower].interestIndex = borrowIndex;
totalBorrows = totalBorrowsNew;
/*
* We invoke doTransferOut for the borrower and the borrowAmount.
* Note: The cToken must handle variations between ERC-20 and ETH underlying.
* On success, the cToken borrowAmount less of cash.
* doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
*/
doTransferOut(borrower, borrowAmount);
/* We emit a Borrow event */
emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew);
}
/**
* @notice Sender repays their own borrow
* @param repayAmount The amount to repay, or -1 for the full outstanding amount
*/
function repayBorrowInternal(uint repayAmount) internal nonReentrant {
accrueInterest();
// repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
repayBorrowFresh(msg.sender, msg.sender, repayAmount);
}
/**
* @notice Sender repays a borrow belonging to borrower
* @param borrower the account with the debt being payed off
* @param repayAmount The amount to repay, or -1 for the full outstanding amount
*/
function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant {
accrueInterest();
// repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
repayBorrowFresh(msg.sender, borrower, repayAmount);
}
// Testing function
function getAccountBorrows(address borrower) public view returns(uint principal, uint interestIndex) {
principal = accountBorrows[borrower].principal;
interestIndex = accountBorrows[borrower].interestIndex;
}
/**
* @notice Borrows are repaid by another user (possibly the borrower).
* @param payer the account paying off the borrow
* @param borrower the account with the debt being payed off
* @param repayAmount the amount of underlying tokens being returned, or -1 for the full outstanding amount
* @return (uint) the actual repayment amount.
*/
function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint) {
/* Fail if repayBorrow not allowed */
uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount);
if (allowed != 0) {
revert RepayBorrowComptrollerRejection(allowed);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
revert RepayBorrowFreshnessCheck();
}
/* We fetch the amount the borrower owes, with accumulated interest */
uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower);
/* If repayAmount == -1, repayAmount = accountBorrows */
uint repayAmountFinal = repayAmount == type(uint).max ? accountBorrowsPrev : repayAmount;
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We call doTransferIn for the payer and the repayAmount
* Note: The cToken must handle variations between ERC-20 and ETH underlying.
* On success, the cToken holds an additional repayAmount of cash.
* doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.
* it returns the amount actually transferred, in case of a fee.
*/
uint actualRepayAmount = doTransferIn(payer, repayAmountFinal);
/*
* We calculate the new borrower and total borrow balances, failing on underflow:
* accountBorrowsNew = accountBorrows - actualRepayAmount
* totalBorrowsNew = totalBorrows - actualRepayAmount
*/
uint accountBorrowsNew = accountBorrowsPrev - actualRepayAmount;
uint totalBorrowsNew = totalBorrows - actualRepayAmount;
/* We write the previously calculated values into storage */
accountBorrows[borrower].principal = accountBorrowsNew;
accountBorrows[borrower].interestIndex = borrowIndex;
totalBorrows = totalBorrowsNew;
/* We emit a RepayBorrow event */
emit RepayBorrow(payer, borrower, actualRepayAmount, accountBorrowsNew, totalBorrowsNew);
return actualRepayAmount;
}
/**
* @notice The sender liquidates the borrowers collateral.
* The collateral seized is transferred to the liquidator.
* @param borrower The borrower of this cToken to be liquidated
* @param cTokenCollateral The market in which to seize collateral from the borrower
* @param repayAmount The amount of the underlying borrowed asset to repay
*/
function liquidateBorrowInternal(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal nonReentrant {
accrueInterest();
uint error = cTokenCollateral.accrueInterest();
if (error != NO_ERROR) {
// accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
revert LiquidateAccrueCollateralInterestFailed(error);
}
// liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to
liquidateBorrowFresh(msg.sender, borrower, repayAmount, cTokenCollateral);
}
/**
* @notice The liquidator liquidates the borrowers collateral.
* The collateral seized is transferred to the liquidator.
* @param borrower The borrower of this cToken to be liquidated
* @param liquidator The address repaying the borrow and seizing collateral
* @param cTokenCollateral The market in which to seize collateral from the borrower
* @param repayAmount The amount of the underlying borrowed asset to repay
*/
function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CTokenInterface cTokenCollateral) internal {
/* Fail if liquidate not allowed */
uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount);
if (allowed != 0) {
revert LiquidateComptrollerRejection(allowed);
}
/* Verify market's block number equals current block number */
if (accrualBlockNumber != getBlockNumber()) {
revert LiquidateFreshnessCheck();
}
/* Verify cTokenCollateral market's block number equals current block number */
if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) {
revert LiquidateCollateralFreshnessCheck();
}
/* Fail if borrower = liquidator */
if (borrower == liquidator) {
revert LiquidateLiquidatorIsBorrower();
}
/* Fail if repayAmount = 0 */
if (repayAmount == 0) {
revert LiquidateCloseAmountIsZero();
}
/* Fail if repayAmount = -1 */
if (repayAmount == type(uint).max) {
revert LiquidateCloseAmountIsUintMax();
}
/* Fail if repayBorrow fails */
uint actualRepayAmount = repayBorrowFresh(liquidator, borrower, repayAmount);
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/* We calculate the number of collateral tokens that will be seized */
(uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens(address(this), address(cTokenCollateral), actualRepayAmount);
require(amountSeizeError == NO_ERROR, "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED");
/* Revert if borrower collateral token balance < seizeTokens */
require(cTokenCollateral.balanceOf(borrower) >= seizeTokens, "LIQUIDATE_SEIZE_TOO_MUCH");
// If this is also the collateral, run seizeInternal to avoid re-entrancy, otherwise make an external call
if (address(cTokenCollateral) == address(this)) {
seizeInternal(address(this), liquidator, borrower, seizeTokens);
} else {
require(cTokenCollateral.seize(liquidator, borrower, seizeTokens) == NO_ERROR, "token seizure failed");
}
/* We emit a LiquidateBorrow event */
emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(cTokenCollateral), seizeTokens);
}
/**
* @notice Transfers collateral tokens (this market) to the liquidator.
* @dev Will fail unless called by another cToken during the process of liquidation.
* Its absolutely critical to use msg.sender as the borrowed cToken and not a parameter.
* @param liquidator The account receiving seized collateral
* @param borrower The account having collateral seized
* @param seizeTokens The number of cTokens to seize
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function seize(address liquidator, address borrower, uint seizeTokens) override external nonReentrant returns (uint) {
seizeInternal(msg.sender, liquidator, borrower, seizeTokens);
return NO_ERROR;
}
/**
* @notice Transfers collateral tokens (this market) to the liquidator.
* @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another CToken.
* Its absolutely critical to use msg.sender as the seizer cToken and not a parameter.
* @param seizerToken The contract seizing the collateral (i.e. borrowed cToken)
* @param liquidator The account receiving seized collateral
* @param borrower The account having collateral seized
* @param seizeTokens The number of cTokens to seize
*/
function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal {
/* Fail if seize not allowed */
uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);
if (allowed != 0) {
revert LiquidateSeizeComptrollerRejection(allowed);
}
/* Fail if borrower = liquidator */
if (borrower == liquidator) {
revert LiquidateSeizeLiquidatorIsBorrower();
}
/*
* We calculate the new borrower and liquidator token balances, failing on underflow/overflow:
* borrowerTokensNew = accountTokens[borrower] - seizeTokens
* liquidatorTokensNew = accountTokens[liquidator] + seizeTokens
*/
uint protocolSeizeTokens = mul_(seizeTokens, Exp({mantissa: protocolSeizeShareMantissa}));
uint liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;
Exp memory exchangeRate = Exp({mantissa: exchangeRateStoredInternal()});
uint protocolSeizeAmount = mul_ScalarTruncate(exchangeRate, protocolSeizeTokens);
uint totalReservesNew = totalReserves + protocolSeizeAmount;
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/* We write the calculated values into storage */
totalReserves = totalReservesNew;
totalSupply = totalSupply - protocolSeizeTokens;
accountTokens[borrower] = accountTokens[borrower] - seizeTokens;
accountTokens[liquidator] = accountTokens[liquidator] + liquidatorSeizeTokens;
/* Emit a Transfer event */
emit Transfer(borrower, liquidator, liquidatorSeizeTokens);
emit Transfer(borrower, address(this), protocolSeizeTokens);
emit ReservesAdded(address(this), protocolSeizeAmount, totalReservesNew);
}
/*** Admin Functions ***/
/**
* @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
* @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
* @param newPendingAdmin New pending admin.
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setPendingAdmin(address payable newPendingAdmin) override external returns (uint) {
// Check caller = admin
if (msg.sender != admin) {
revert SetPendingAdminOwnerCheck();
}
// Save current value, if any, for inclusion in log
address oldPendingAdmin = pendingAdmin;
// Store pendingAdmin with value newPendingAdmin
pendingAdmin = newPendingAdmin;
// Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);
return NO_ERROR;
}
/**
* @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
* @dev Admin function for pending admin to accept role and update admin
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _acceptAdmin() override external returns (uint) {
// Check caller is pendingAdmin and pendingAdmin ≠ address(0)
if (msg.sender != pendingAdmin || msg.sender == address(0)) {
revert AcceptAdminPendingAdminCheck();
}
// Save current values for inclusion in log
address oldAdmin = admin;
address oldPendingAdmin = pendingAdmin;
// Store admin with value pendingAdmin
admin = pendingAdmin;
// Clear the pending value
pendingAdmin = payable(address(0));
emit NewAdmin(oldAdmin, admin);
emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);
return NO_ERROR;
}
/**
* @notice Sets a new comptroller for the market
* @dev Admin function to set a new comptroller
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setComptroller(ComptrollerInterface newComptroller) override public returns (uint) {
// Check caller is admin
if (msg.sender != admin) {
revert SetComptrollerOwnerCheck();
}
ComptrollerInterface oldComptroller = comptroller;
// Ensure invoke comptroller.isComptroller() returns true
require(newComptroller.isComptroller(), "marker method returned false");
// Set market's comptroller to newComptroller
comptroller = newComptroller;
// Emit NewComptroller(oldComptroller, newComptroller)
emit NewComptroller(oldComptroller, newComptroller);
return NO_ERROR;
}
/**
* @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
* @dev Admin function to accrue interest and set a new reserve factor
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setReserveFactor(uint newReserveFactorMantissa) override external nonReentrant returns (uint) {
accrueInterest();
// _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to.
return _setReserveFactorFresh(newReserveFactorMantissa);
}
/**
* @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)
* @dev Admin function to set a new reserve factor
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {
// Check caller is admin
if (msg.sender != admin) {
revert SetReserveFactorAdminCheck();
}
// Verify market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
revert SetReserveFactorFreshCheck();
}
// Check newReserveFactor ≤ maxReserveFactor
if (newReserveFactorMantissa > reserveFactorMaxMantissa) {
revert SetReserveFactorBoundsCheck();
}
uint oldReserveFactorMantissa = reserveFactorMantissa;
reserveFactorMantissa = newReserveFactorMantissa;
emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);
return NO_ERROR;
}
/**
* @notice Accrues interest and reduces reserves by transferring from msg.sender
* @param addAmount Amount of addition to reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _addReservesInternal(uint addAmount) internal nonReentrant returns (uint) {
accrueInterest();
// _addReservesFresh emits reserve-addition-specific logs on errors, so we don't need to.
_addReservesFresh(addAmount);
return NO_ERROR;
}
/**
* @notice Add reserves by transferring from caller
* @dev Requires fresh interest accrual
* @param addAmount Amount of addition to reserves
* @return (uint, uint) An error code (0=success, otherwise a failure (see ErrorReporter.sol for details)) and the actual amount added, net token fees
*/
function _addReservesFresh(uint addAmount) internal returns (uint, uint) {
// totalReserves + actualAddAmount
uint totalReservesNew;
uint actualAddAmount;
// We fail gracefully unless market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
revert AddReservesFactorFreshCheck(actualAddAmount);
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
/*
* We call doTransferIn for the caller and the addAmount
* Note: The cToken must handle variations between ERC-20 and ETH underlying.
* On success, the cToken holds an additional addAmount of cash.
* doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.
* it returns the amount actually transferred, in case of a fee.
*/
actualAddAmount = doTransferIn(msg.sender, addAmount);
totalReservesNew = totalReserves + actualAddAmount;
// Store reserves[n+1] = reserves[n] + actualAddAmount
totalReserves = totalReservesNew;
/* Emit NewReserves(admin, actualAddAmount, reserves[n+1]) */
emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);
/* Return (NO_ERROR, actualAddAmount) */
return (NO_ERROR, actualAddAmount);
}
/**
* @notice Accrues interest and reduces reserves by transferring to admin
* @param reduceAmount Amount of reduction to reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _reduceReserves(uint reduceAmount) override external nonReentrant returns (uint) {
accrueInterest();
// _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to.
return _reduceReservesFresh(reduceAmount);
}
/**
* @notice Reduces reserves by transferring to admin
* @dev Requires fresh interest accrual
* @param reduceAmount Amount of reduction to reserves
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _reduceReservesFresh(uint reduceAmount) internal returns (uint) {
// totalReserves - reduceAmount
uint totalReservesNew;
// Check caller is admin
if (msg.sender != admin) {
revert ReduceReservesAdminCheck();
}
// We fail gracefully unless market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
revert ReduceReservesFreshCheck();
}
// Fail gracefully if protocol has insufficient underlying cash
if (getCashPrior() < reduceAmount) {
revert ReduceReservesCashNotAvailable();
}
// Check reduceAmount ≤ reserves[n] (totalReserves)
if (reduceAmount > totalReserves) {
revert ReduceReservesCashValidation();
}
/////////////////////////
// EFFECTS & INTERACTIONS
// (No safe failures beyond this point)
totalReservesNew = totalReserves - reduceAmount;
// Store reserves[n+1] = reserves[n] - reduceAmount
totalReserves = totalReservesNew;
// doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
doTransferOut(admin, reduceAmount);
emit ReservesReduced(admin, reduceAmount, totalReservesNew);
return NO_ERROR;
}
/**
* @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh
* @dev Admin function to accrue interest and update the interest rate model
* @param newInterestRateModel the new interest rate model to use
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setInterestRateModel(InterestRateModel newInterestRateModel) override public returns (uint) {
accrueInterest();
// _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to.
return _setInterestRateModelFresh(newInterestRateModel);
}
/**
* @notice updates the interest rate model (*requires fresh interest accrual)
* @dev Admin function to update the interest rate model
* @param newInterestRateModel the new interest rate model to use
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) {
// Used to store old model for use in the event that is emitted on success
InterestRateModel oldInterestRateModel;
// Check caller is admin
if (msg.sender != admin) {
revert SetInterestRateModelOwnerCheck();
}
// We fail gracefully unless market's block number equals current block number
if (accrualBlockNumber != getBlockNumber()) {
revert SetInterestRateModelFreshCheck();
}
// Track the market's current interest rate model
oldInterestRateModel = interestRateModel;
// Ensure invoke newInterestRateModel.isInterestRateModel() returns true
require(newInterestRateModel.isInterestRateModel(), "marker method returned false");
// Set the interest rate model to newInterestRateModel
interestRateModel = newInterestRateModel;
// Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)
emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);
return NO_ERROR;
}
/*** Safe Token ***/
/**
* @notice Gets balance of this contract in terms of the underlying
* @dev This excludes the value of the current message, if any
* @return The quantity of underlying owned by this contract
*/
function getCashPrior() virtual internal view returns (uint);
/**
* @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee.
* This may revert due to insufficient balance or insufficient allowance.
*/
function doTransferIn(address from, uint amount) virtual internal returns (uint);
/**
* @dev Performs a transfer out, ideally returning an explanatory error code upon failure rather than reverting.
* If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract.
* If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions.
*/
function doTransferOut(address payable to, uint amount) virtual internal;
/*** Reentrancy Guard ***/
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
*/
modifier nonReentrant() {
require(_notEntered, "re-entered");
_notEntered = false;
_;
_notEntered = true; // get a gas-refund post-Istanbul
}
}
================================================
FILE: protocols/compound-v2/src/CTokenInterfaces.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./ComptrollerInterface.sol";
import "./InterestRateModel.sol";
import "./EIP20NonStandardInterface.sol";
import "./ErrorReporter.sol";
contract CTokenStorage {
/**
* @dev Guard variable for re-entrancy checks
*/
bool internal _notEntered;
/**
* @notice EIP-20 token name for this token
*/
string public name;
/**
* @notice EIP-20 token symbol for this token
*/
string public symbol;
/**
* @notice EIP-20 token decimals for this token
*/
uint8 public decimals;
// Maximum borrow rate that can ever be applied (.0005% / block)
uint internal constant borrowRateMaxMantissa = 0.0005e16;
// Maximum fraction of interest that can be set aside for reserves
uint internal constant reserveFactorMaxMantissa = 1e18;
/**
* @notice Administrator for this contract
*/
address payable public admin;
/**
* @notice Pending administrator for this contract
*/
address payable public pendingAdmin;
/**
* @notice Contract which oversees inter-cToken operations
*/
ComptrollerInterface public comptroller;
/**
* @notice Model which tells what the current interest rate should be
*/
InterestRateModel public interestRateModel;
// Initial exchange rate used when minting the first CTokens (used when totalSupply = 0)
uint internal initialExchangeRateMantissa;
/**
* @notice Fraction of interest currently set aside for reserves
*/
uint public reserveFactorMantissa;
/**
* @notice Block number that interest was last accrued at
*/
uint public accrualBlockNumber;
/**
* @notice Accumulator of the total earned interest rate since the opening of the market
*/
uint public borrowIndex;
/**
* @notice Total amount of outstanding borrows of the underlying in this market
*/
uint public totalBorrows;
/**
* @notice Total amount of reserves of the underlying held in this market
*/
uint public totalReserves;
/**
* @notice Total number of tokens in circulation
*/
uint public totalSupply;
// Official record of token balances for each account
mapping (address => uint) internal accountTokens;
// Approved token transfer amounts on behalf of others
mapping (address => mapping (address => uint)) internal transferAllowances;
/**
* @notice Container for borrow balance information
* @member principal Total balance (with accrued interest), after applying the most recent balance-changing action
* @member interestIndex Global borrowIndex as of the most recent balance-changing action
*/
struct BorrowSnapshot {
uint principal;
uint interestIndex;
}
// Mapping of account addresses to outstanding borrow balances
mapping(address => BorrowSnapshot) internal accountBorrows;
/**
* @notice Share of seized collateral that is added to reserves
*/
uint public constant protocolSeizeShareMantissa = 2.8e16; //2.8%
}
abstract contract CTokenInterface is CTokenStorage {
/**
* @notice Indicator that this is a CToken contract (for inspection)
*/
bool public constant isCToken = true;
/*** Market Events ***/
/**
* @notice Event emitted when interest is accrued
*/
event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows);
/**
* @notice Event emitted when tokens are minted
*/
event Mint(address minter, uint mintAmount, uint mintTokens);
/**
* @notice Event emitted when tokens are redeemed
*/
event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);
/**
* @notice Event emitted when underlying is borrowed
*/
event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows);
/**
* @notice Event emitted when a borrow is repaid
*/
event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows);
/**
* @notice Event emitted when a borrow is liquidated
*/
event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens);
/*** Admin Events ***/
/**
* @notice Event emitted when pendingAdmin is changed
*/
event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);
/**
* @notice Event emitted when pendingAdmin is accepted, which means admin is updated
*/
event NewAdmin(address oldAdmin, address newAdmin);
/**
* @notice Event emitted when comptroller is changed
*/
event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);
/**
* @notice Event emitted when interestRateModel is changed
*/
event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel);
/**
* @notice Event emitted when the reserve factor is changed
*/
event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa);
/**
* @notice Event emitted when the reserves are added
*/
event ReservesAdded(address benefactor, uint addAmount, uint newTotalReserves);
/**
* @notice Event emitted when the reserves are reduced
*/
event ReservesReduced(address admin, uint reduceAmount, uint newTotalReserves);
/**
* @notice EIP20 Transfer event
*/
event Transfer(address indexed from, address indexed to, uint amount);
/**
* @notice EIP20 Approval event
*/
event Approval(address indexed owner, address indexed spender, uint amount);
/*** User Interface ***/
function transfer(address dst, uint amount) virtual external returns (bool);
function transferFrom(address src, address dst, uint amount) virtual external returns (bool);
function approve(address spender, uint amount) virtual external returns (bool);
function allowance(address owner, address spender) virtual external view returns (uint);
function balanceOf(address owner) virtual external view returns (uint);
function balanceOfUnderlying(address owner) virtual external returns (uint);
function getAccountSnapshot(address account) virtual external view returns (uint, uint, uint, uint);
function borrowRatePerBlock() virtual external view returns (uint);
function supplyRatePerBlock() virtual external view returns (uint);
function totalBorrowsCurrent() virtual external returns (uint);
function borrowBalanceCurrent(address account) virtual external returns (uint);
function borrowBalanceStored(address account) virtual external view returns (uint);
function exchangeRateCurrent() virtual external returns (uint);
function exchangeRateStored() virtual external view returns (uint);
function getCash() virtual external view returns (uint);
function accrueInterest() virtual external returns (uint);
function seize(address liquidator, address borrower, uint seizeTokens) virtual external returns (uint);
/*** Admin Functions ***/
function _setPendingAdmin(address payable newPendingAdmin) virtual external returns (uint);
function _acceptAdmin() virtual external returns (uint);
function _setComptroller(ComptrollerInterface newComptroller) virtual external returns (uint);
function _setReserveFactor(uint newReserveFactorMantissa) virtual external returns (uint);
function _reduceReserves(uint reduceAmount) virtual external returns (uint);
function _setInterestRateModel(InterestRateModel newInterestRateModel) virtual external returns (uint);
}
contract CErc20Storage {
/**
* @notice Underlying asset for this CToken
*/
address public underlying;
}
abstract contract CErc20Interface is CErc20Storage {
/*** User Interface ***/
function mint(uint mintAmount) virtual external returns (uint);
function redeem(uint redeemTokens) virtual external returns (uint);
function redeemUnderlying(uint redeemAmount) virtual external returns (uint);
function borrow(uint borrowAmount) virtual external returns (uint);
function repayBorrow(uint repayAmount) virtual external returns (uint);
function repayBorrowBehalf(address borrower, uint repayAmount) virtual external returns (uint);
function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) virtual external returns (uint);
function sweepToken(EIP20NonStandardInterface token) virtual external;
/*** Admin Functions ***/
function _addReserves(uint addAmount) virtual external returns (uint);
}
contract CDelegationStorage {
/**
* @notice Implementation address for this contract
*/
address public implementation;
}
abstract contract CDelegatorInterface is CDelegationStorage {
/**
* @notice Emitted when implementation is changed
*/
event NewImplementation(address oldImplementation, address newImplementation);
/**
* @notice Called by the admin to update the implementation of the delegator
* @param implementation_ The address of the new implementation for delegation
* @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
* @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
*/
function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) virtual external;
}
abstract contract CDelegateInterface is CDelegationStorage {
/**
* @notice Called by the delegator on a delegate to initialize it for duty
* @dev Should revert if any issues arise which make it unfit for delegation
* @param data The encoded bytes data for any initialization
*/
function _becomeImplementation(bytes memory data) virtual external;
/**
* @notice Called by the delegator on a delegate to forfeit its responsibility
*/
function _resignImplementation() virtual external;
}
================================================
FILE: protocols/compound-v2/src/Comptroller.sol
================================================
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
import "./CToken.sol";
import "./ErrorReporter.sol";
import "./PriceOracle.sol";
import "./ComptrollerInterface.sol";
import "./ComptrollerStorage.sol";
import "./Unitroller.sol";
import "./Governance/Comp.sol";
/**
* @title Compound's Comptroller Contract
* @author Compound
*/
contract Comptroller is ComptrollerV7Storage, ComptrollerInterface, ComptrollerErrorReporter, ExponentialNoError {
/// @notice Emitted when an admin supports a market
event MarketListed(CToken cToken);
/// @notice Emitted when an account enters a market
event MarketEntered(CToken cToken, address account);
/// @notice Emitted when an account exits a market
event MarketExited(CToken cToken, address account);
/// @notice Emitted when close factor is changed by admin
event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);
/// @notice Emitted when a collateral factor is changed by admin
event NewCollateralFactor(CToken cToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);
/// @notice Emitted when liquidation incentive is changed by admin
event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);
/// @notice Emitted when price oracle is changed
event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);
/// @notice Emitted when pause guardian is changed
event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);
/// @notice Emitted when an action is paused globally
event ActionPaused(string action, bool pauseState);
/// @notice Emitted when an action is paused on a market
event ActionPaused(CToken cToken, string action, bool pauseState);
/// @notice Emitted when a new borrow-side COMP speed is calculated for a market
event CompBorrowSpeedUpdated(CToken indexed cToken, uint newSpeed);
/// @notice Emitted when a new supply-side COMP speed is calculated for a market
event CompSupplySpeedUpdated(CToken indexed cToken, uint newSpeed);
/// @notice Emitted when a new COMP speed is set for a contributor
event ContributorCompSpeedUpdated(address indexed contributor, uint newSpeed);
/// @notice Emitted when COMP is distributed to a supplier
event DistributedSupplierComp(CToken indexed cToken, address indexed supplier, uint compDelta, uint compSupplyIndex);
/// @notice Emitted when COMP is distributed to a borrower
event DistributedBorrowerComp(CToken indexed cToken, address indexed borrower, uint compDelta, uint compBorrowIndex);
/// @notice Emitted when borrow cap for a cToken is changed
event NewBorrowCap(CToken indexed cToken, uint newBorrowCap);
/// @notice Emitted when borrow cap guardian is changed
event NewBorrowCapGuardian(address oldBorrowCapGuardian, address newBorrowCapGuardian);
/// @notice Emitted when COMP is granted by admin
event CompGranted(address recipient, uint amount);
/// @notice Emitted when COMP accrued for a user has been manually adjusted.
event CompAccruedAdjusted(address indexed user, uint oldCompAccrued, uint newCompAccrued);
/// @notice Emitted when COMP receivable for a user has been updated.
event CompReceivableUpdated(address indexed user, uint oldCompReceivable, uint newCompReceivable);
/// @notice The initial COMP index for a market
uint224 public constant compInitialIndex = 1e36;
// closeFactorMantissa must be strictly greater than this value
uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05
// closeFactorMantissa must not exceed this value
uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9
// No collateralFactorMantissa may exceed this value
uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9
constructor() {
admin = msg.sender;
}
/*** Assets You Are In ***/
/**
* @notice Returns the assets an account has entered
* @param account The address of the account to pull assets for
* @return A dynamic list with the assets the account has entered
*/
function getAssetsIn(address account) external view returns (CToken[] memory) {
CToken[] memory assetsIn = accountAssets[account];
return assetsIn;
}
/**
* @notice Returns whether the given account is entered in the given asset
* @param account The address of the account to check
* @param cToken The cToken to check
* @return True if the account is in the asset, otherwise false.
*/
function checkMembership(address account, CToken cToken) external view returns (bool) {
return markets[address(cToken)].accountMembership[account];
}
/**
* @notice Add assets to be included in account liquidity calculation
* @param cTokens The list of addresses of the cToken markets to be enabled
* @return Success indicator for whether each corresponding market was entered
*/
function enterMarkets(address[] memory cTokens) override public returns (uint[] memory) {
uint len = cTokens.length;
uint[] memory results = new uint[](len);
for (uint i = 0; i < len; i++) {
CToken cToken = CToken(cTokens[i]);
results[i] = uint(addToMarketInternal(cToken, msg.sender));
}
return results;
}
/**
* @notice Add the market to the borrower's "assets in" for liquidity calculations
* @param cToken The market to enter
* @param borrower The address of the account to modify
* @return Success indicator for whether the market was entered
*/
function addToMarketInternal(CToken cToken, address borrower) internal returns (Error) {
Market storage marketToJoin = markets[address(cToken)];
if (!marketToJoin.isListed) {
// market is not listed, cannot join
return Error.MARKET_NOT_LISTED;
}
if (marketToJoin.accountMembership[borrower] == true) {
// already joined
return Error.NO_ERROR;
}
// survived the gauntlet, add to list
// NOTE: we store these somewhat redundantly as a significant optimization
// this avoids having to iterate through the list for the most common use cases
// that is, only when we need to perform liquidity checks
// and not whenever we want to check if an account is in a particular market
marketToJoin.accountMembership[borrower] = true;
accountAssets[borrower].push(cToken);
emit MarketEntered(cToken, borrower);
return Error.NO_ERROR;
}
/**
* @notice Removes asset from sender's account liquidity calculation
* @dev Sender must not have an outstanding borrow balance in the asset,
* or be providing necessary collateral for an outstanding borrow.
* @param cTokenAddress The address of the asset to be removed
* @return Whether or not the account successfully exited the market
*/
function exitMarket(address cTokenAddress) override external returns (uint) {
CToken cToken = CToken(cTokenAddress);
/* Get sender tokensHeld and amountOwed underlying from the cToken */
(uint oErr, uint tokensHeld, uint amountOwed, ) = cToken.getAccountSnapshot(msg.sender);
require(oErr == 0, "exitMarket: getAccountSnapshot failed"); // semi-opaque error code
/* Fail if the sender has a borrow balance */
if (amountOwed != 0) {
return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);
}
/* Fail if the sender is not permitted to redeem all of their tokens */
uint allowed = redeemAllowedInternal(cTokenAddress, msg.sender, tokensHeld);
if (allowed != 0) {
return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);
}
Market storage marketToExit = markets[address(cToken)];
/* Return true if the sender is not already ‘in’ the market */
if (!marketToExit.accountMembership[msg.sender]) {
return uint(Error.NO_ERROR);
}
/* Set cToken account membership to false */
delete marketToExit.accountMembership[msg.sender];
/* Delete cToken from the account’s list of assets */
// load into memory for faster iteration
CToken[] memory userAssetList = accountAssets[msg.sender];
uint len = userAssetList.length;
uint assetIndex = len;
for (uint i = 0; i < len; i++) {
if (userAssetList[i] == cToken) {
assetIndex = i;
break;
}
}
// We *must* have found the asset in the list or our redundant data structure is broken
assert(assetIndex < len);
// copy last item in list to location of item to be removed, reduce length by 1
CToken[] storage storedList = accountAssets[msg.sender];
storedList[assetIndex] = storedList[storedList.length - 1];
storedList.pop();
emit MarketExited(cToken, msg.sender);
return uint(Error.NO_ERROR);
}
/*** Policy Hooks ***/
/**
* @notice Checks if the account should be allowed to mint tokens in the given market
* @param cToken The market to verify the mint against
* @param minter The account which would get the minted tokens
* @param mintAmount The amount of underlying being supplied to the market in exchange for tokens
* @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
*/
function mintAllowed(address cToken, address minter, uint mintAmount) override external returns (uint) {
// Pausing is a very serious situation - we revert to sound the alarms
require(!mintGuardianPaused[cToken], "mint is paused");
// Shh - currently unused
minter;
mintAmount;
if (!markets[cToken].isListed) {
return uint(Error.MARKET_NOT_LISTED);
}
// Keep the flywheel moving
updateCompSupplyIndex(cToken);
distributeSupplierComp(cToken, minter);
return uint(Error.NO_ERROR);
}
/**
* @notice Validates mint and reverts on rejection. May emit logs.
* @param cToken Asset being minted
* @param minter The address minting the tokens
* @param actualMintAmount The amount of the underlying asset being minted
gitextract_drv2awpe/
├── CONTRIBUTING.md
├── LICENSE
├── PROPERTIES.md
├── README.md
├── package.json
└── protocols/
├── compound-v2/
│ ├── .gitignore
│ ├── .gitmodules
│ ├── LICENSE
│ ├── README.md
│ ├── foundry.toml
│ ├── package.json
│ ├── remappings.txt
│ ├── script/
│ │ └── Counter.s.sol
│ ├── src/
│ │ ├── BaseJumpRateModelV2.sol
│ │ ├── CDaiDelegate.sol
│ │ ├── CErc20.sol
│ │ ├── CErc20Delegate.sol
│ │ ├── CErc20Delegator.sol
│ │ ├── CErc20Immutable.sol
│ │ ├── CEther.sol
│ │ ├── CToken.sol
│ │ ├── CTokenInterfaces.sol
│ │ ├── Comptroller.sol
│ │ ├── ComptrollerG7.sol
│ │ ├── ComptrollerInterface.sol
│ │ ├── ComptrollerStorage.sol
│ │ ├── DAIInterestRateModelV3.sol
│ │ ├── EIP20Interface.sol
│ │ ├── EIP20NonStandardInterface.sol
│ │ ├── ErrorReporter.sol
│ │ ├── ExponentialNoError.sol
│ │ ├── Governance/
│ │ │ ├── Comp.sol
│ │ │ ├── GovernorAlpha.sol
│ │ │ ├── GovernorBravoDelegate.sol
│ │ │ ├── GovernorBravoDelegateG1.sol
│ │ │ ├── GovernorBravoDelegateG2.sol
│ │ │ ├── GovernorBravoDelegator.sol
│ │ │ └── GovernorBravoInterfaces.sol
│ │ ├── InterestRateModel.sol
│ │ ├── JumpRateModel.sol
│ │ ├── JumpRateModelV2.sol
│ │ ├── Lens/
│ │ │ └── CompoundLens.sol
│ │ ├── Maximillion.sol
│ │ ├── PriceOracle.sol
│ │ ├── Reservoir.sol
│ │ ├── SafeMath.sol
│ │ ├── SimplePriceOracle.sol
│ │ ├── Timelock.sol
│ │ ├── Unitroller.sol
│ │ └── WhitePaperInterestRateModel.sol
│ └── test/
│ ├── core.t.sol
│ └── mocks/
│ └── ERC20.sol
├── olympus-v1/
│ ├── .gitignore
│ ├── .gitmodules
│ ├── LICENSE
│ ├── README.md
│ ├── foundry.toml
│ ├── package.json
│ ├── remappings.txt
│ ├── script/
│ │ └── Counter.s.sol
│ ├── src/
│ │ ├── BondDepository.sol
│ │ ├── CVXBondDepository.sol
│ │ ├── OlympusERC20.sol
│ │ ├── RedeemHelper.sol
│ │ ├── RiskFreeValueOfNonReserve.sol
│ │ ├── Staking.sol
│ │ ├── StakingDistributor.sol
│ │ ├── StakingHelper.sol
│ │ ├── StakingWarmup.sol
│ │ ├── StandardBondingCalculator.sol
│ │ ├── Treasury.sol
│ │ ├── mocks/
│ │ │ ├── DAI.sol
│ │ │ ├── Frax.sol
│ │ │ ├── MockBondDepository.sol
│ │ │ └── MockTreasury.sol
│ │ ├── sOlympusERC20.sol
│ │ ├── wETHBondDepository.sol
│ │ └── wOHM.sol
│ └── test/
│ ├── IUniswapV2Pair.sol
│ └── core.t.sol
├── tombfinance/
│ ├── .gitignore
│ ├── .gitmodules
│ ├── README.md
│ ├── foundry.toml
│ ├── remappings.txt
│ ├── script/
│ │ └── Counter.s.sol
│ ├── src/
│ │ ├── Distributor.sol
│ │ ├── DummyToken.sol
│ │ ├── Masonry.sol
│ │ ├── Migrations.sol
│ │ ├── Oracle.sol
│ │ ├── SimpleERCFund.sol
│ │ ├── TBond.sol
│ │ ├── TShare.sol
│ │ ├── TaxOffice.sol
│ │ ├── TaxOfficeV2.sol
│ │ ├── TaxOracle.sol
│ │ ├── Timelock.sol
│ │ ├── Tomb.sol
│ │ ├── Treasury.sol
│ │ ├── distribution/
│ │ │ ├── TShareRewardPool.sol
│ │ │ ├── TombGenesisRewardPool.sol
│ │ │ └── TombRewardPool.sol
│ │ ├── interfaces/
│ │ │ ├── IBasisAsset.sol
│ │ │ ├── IDecimals.sol
│ │ │ ├── IDistributor.sol
│ │ │ ├── IERC20.sol
│ │ │ ├── IMasonry.sol
│ │ │ ├── IOracle.sol
│ │ │ ├── IShare.sol
│ │ │ ├── ISimpleERCFund.sol
│ │ │ ├── ITShareRewardPool.sol
│ │ │ ├── ITaxable.sol
│ │ │ ├── ITreasury.sol
│ │ │ ├── IUniswapV2Callee.sol
│ │ │ ├── IUniswapV2ERC20.sol
│ │ │ ├── IUniswapV2Factory.sol
│ │ │ ├── IUniswapV2Pair.sol
│ │ │ ├── IUniswapV2Router.sol
│ │ │ └── IWrappedFtm.sol
│ │ ├── lib/
│ │ │ ├── Babylonian.sol
│ │ │ ├── FixedPoint.sol
│ │ │ ├── Safe112.sol
│ │ │ ├── SafeMath8.sol
│ │ │ ├── UQ112x112.sol
│ │ │ ├── UniswapV2Library.sol
│ │ │ └── UniswapV2OracleLibrary.sol
│ │ ├── owner/
│ │ │ └── Operator.sol
│ │ └── utils/
│ │ ├── ContractGuard.sol
│ │ └── Epoch.sol
│ └── test/
│ ├── core.t.sol
│ ├── mocks/
│ │ ├── MockUniPair.sol
│ │ └── MockWeth.sol
│ └── v2-core/
│ ├── UniswapV2ERC20.sol
│ ├── UniswapV2Factory.sol
│ ├── UniswapV2Pair.sol
│ ├── interfaces/
│ │ ├── IUniswapV2Callee.sol
│ │ ├── IUniswapV2ERC20.sol
│ │ ├── IUniswapV2Factory.sol
│ │ └── IUniswapV2Pair.sol
│ ├── libraries/
│ │ ├── Math.sol
│ │ ├── SafeMath.sol
│ │ └── UQ112x112.sol
│ └── test/
│ └── ERC20.sol
└── uniswap-v2/
├── .gitignore
├── .gitmodules
├── README.md
├── foundry.toml
├── remappings.txt
├── script/
│ └── Counter.s.sol
├── src/
│ ├── UniswapV2ERC20.sol
│ ├── UniswapV2Factory.sol
│ ├── UniswapV2Pair.sol
│ ├── contracts/
│ │ ├── UniswapV2Migrator.sol
│ │ ├── UniswapV2Router01.sol
│ │ ├── UniswapV2Router02.sol
│ │ ├── examples/
│ │ │ ├── ExampleComputeLiquidityValue.sol
│ │ │ ├── ExampleFlashSwap.sol
│ │ │ ├── ExampleOracleSimple.sol
│ │ │ ├── ExampleSlidingWindowOracle.sol
│ │ │ ├── ExampleSwapToPrice.sol
│ │ │ └── README.md
│ │ ├── interfaces/
│ │ │ ├── IUniswapV2Migrator.sol
│ │ │ ├── IUniswapV2Router01.sol
│ │ │ ├── IUniswapV2Router02.sol
│ │ │ ├── IWETH.sol
│ │ │ └── V1/
│ │ │ ├── IUniswapV1Exchange.sol
│ │ │ └── IUniswapV1Factory.sol
│ │ ├── libraries/
│ │ │ ├── UniswapV2Library.sol
│ │ │ ├── UniswapV2LiquidityMathLibrary.sol
│ │ │ └── UniswapV2OracleLibrary.sol
│ │ └── test/
│ │ ├── DeflatingERC20.sol
│ │ ├── ERC20.sol
│ │ ├── RouterEventEmitter.sol
│ │ └── WETH9.sol
│ ├── interfaces/
│ │ ├── IERC20.sol
│ │ ├── IUniswapV2Callee.sol
│ │ ├── IUniswapV2ERC20.sol
│ │ ├── IUniswapV2Factory.sol
│ │ └── IUniswapV2Pair.sol
│ ├── libraries/
│ │ ├── AddressStringUtil.sol
│ │ ├── Babylonian.sol
│ │ ├── BitMath.sol
│ │ ├── FixedPoint.sol
│ │ ├── FullMath.sol
│ │ ├── Math.sol
│ │ ├── PairNamer.sol
│ │ ├── SafeERC20Namer.sol
│ │ ├── SafeMath.sol
│ │ ├── TransferHelper.sol
│ │ └── UQ112x112.sol
│ └── test/
│ ├── ERC20.sol
│ └── core.t.sol
└── test/
├── core.t.sol
└── mocks/
├── MockToken.sol
└── MockWETH.sol
Condensed preview — 196 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,515K chars).
[
{
"path": "CONTRIBUTING.md",
"chars": 6815,
"preview": "# Contributing to Fuzzy DeFi\r\n\r\nFirst, thanks for your interest in contributing to this repository! I welcome and apprec"
},
{
"path": "LICENSE",
"chars": 35182,
"preview": " GNU AFFERO GENERAL PUBLIC LICENSE\r\n Version 3, 19 November 2007\r\n\r\n Copyright "
},
{
"path": "PROPERTIES.md",
"chars": 17105,
"preview": "# Introduction\r\nHere is a list of the property tests for the top five forked protocols. For each property, there is a pe"
},
{
"path": "README.md",
"chars": 1877,
"preview": "# Fuzzy DeFi\r\n\r\n## Properties\r\nThis repository contains code properties for the current top four forked protocols:\r\n1. ["
},
{
"path": "package.json",
"chars": 457,
"preview": "{\r\n \"name\": \"fuzzy-defi\",\r\n \"version\": \"0.0.2\",\r\n \"description\": \"Pre-built security properties for commonly fo"
},
{
"path": "protocols/compound-v2/.gitignore",
"chars": 10,
"preview": "cache\nout\n"
},
{
"path": "protocols/compound-v2/.gitmodules",
"chars": 114,
"preview": "[submodule \"lib/forge-std\"]\n\tpath = lib/forge-std\n\turl = https://github.com/foundry-rs/forge-std\n\tbranch = v1.7.1\n"
},
{
"path": "protocols/compound-v2/LICENSE",
"chars": 1463,
"preview": "Copyright 2020 Compound Labs, Inc.\n\nRedistribution and use in source and binary forms, with or without modification, are"
},
{
"path": "protocols/compound-v2/README.md",
"chars": 7003,
"preview": "# Setup\n1. `forge install`\n2. `forge test --mc TestCore`\n\n## Integration\n1. Follow setup\n2. Add test helpers functions:\n"
},
{
"path": "protocols/compound-v2/foundry.toml",
"chars": 161,
"preview": "[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\"]\n\n[fuzz]\nruns = 10000\n\n# See more config options https://github."
},
{
"path": "protocols/compound-v2/package.json",
"chars": 256,
"preview": "{\n \"name\": \"compound-protocol\",\n \"version\": \"0.2.1\",\n \"description\": \"The Compound Money Market\",\n \"main\": \"index.js"
},
{
"path": "protocols/compound-v2/remappings.txt",
"chars": 264,
"preview": "forge-std/=lib/forge-std/src/\n@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts\n@ope"
},
{
"path": "protocols/compound-v2/script/Counter.s.sol",
"chars": 224,
"preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"forge-std/Script.sol\";\n\ncontract CounterScript "
},
{
"path": "protocols/compound-v2/src/BaseJumpRateModelV2.sol",
"chars": 6423,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./InterestRateModel.sol\";\n\n/**\n * @title Log"
},
{
"path": "protocols/compound-v2/src/CDaiDelegate.sol",
"chars": 7184,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CErc20Delegate.sol\";\n\n/**\n * @title Compoun"
},
{
"path": "protocols/compound-v2/src/CErc20.sol",
"chars": 10565,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CToken.sol\";\n\ninterface CompLike {\n func"
},
{
"path": "protocols/compound-v2/src/CErc20Delegate.sol",
"chars": 1290,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CErc20.sol\";\n\n/**\n * @title Compound's CErc"
},
{
"path": "protocols/compound-v2/src/CErc20Delegator.sol",
"chars": 23212,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CTokenInterfaces.sol\";\n\n/**\n * @title Compo"
},
{
"path": "protocols/compound-v2/src/CErc20Immutable.sol",
"chars": 1533,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CErc20.sol\";\n\n/**\n * @title Compound's CErc"
},
{
"path": "protocols/compound-v2/src/CEther.sol",
"chars": 5411,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CToken.sol\";\n\n/**\n * @title Compound's CEth"
},
{
"path": "protocols/compound-v2/src/CToken.sol",
"chars": 49487,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./ComptrollerInterface.sol\";\nimport \"./CToken"
},
{
"path": "protocols/compound-v2/src/CTokenInterfaces.sol",
"chars": 10216,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./ComptrollerInterface.sol\";\nimport \"./Intere"
},
{
"path": "protocols/compound-v2/src/Comptroller.sol",
"chars": 62536,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\n"
},
{
"path": "protocols/compound-v2/src/ComptrollerG7.sol",
"chars": 56412,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CToken.sol\";\nimport \"./ErrorReporter.sol\";\n"
},
{
"path": "protocols/compound-v2/src/ComptrollerInterface.sol",
"chars": 2773,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nabstract contract ComptrollerInterface {\n /// @not"
},
{
"path": "protocols/compound-v2/src/ComptrollerStorage.sol",
"chars": 5533,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CToken.sol\";\nimport \"./PriceOracle.sol\";\n\nc"
},
{
"path": "protocols/compound-v2/src/DAIInterestRateModelV3.sol",
"chars": 5787,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./JumpRateModelV2.sol\";\n\n/**\n * @title Compo"
},
{
"path": "protocols/compound-v2/src/EIP20Interface.sol",
"chars": 2704,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n/**\n * @title ERC 20 Token Standard Interface\n * htt"
},
{
"path": "protocols/compound-v2/src/EIP20NonStandardInterface.sol",
"chars": 2794,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n/**\n * @title EIP20NonStandardInterface\n * @dev Versi"
},
{
"path": "protocols/compound-v2/src/ErrorReporter.sol",
"chars": 4199,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\ncontract ComptrollerErrorReporter {\n enum Error {\n"
},
{
"path": "protocols/compound-v2/src/ExponentialNoError.sol",
"chars": 5757,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n/**\n * @title Exponential module for storing fixed-pr"
},
{
"path": "protocols/compound-v2/src/Governance/Comp.sol",
"chars": 12633,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\ncontract Comp {\n /// @notice EIP-20 token name for"
},
{
"path": "protocols/compound-v2/src/Governance/GovernorAlpha.sol",
"chars": 15144,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\ncontract GovernorAlpha {\n /// @notice The name of "
},
{
"path": "protocols/compound-v2/src/Governance/GovernorBravoDelegate.sol",
"chars": 21213,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./GovernorBravoInterfaces.sol\";\n\ncontract Gov"
},
{
"path": "protocols/compound-v2/src/Governance/GovernorBravoDelegateG1.sol",
"chars": 18969,
"preview": "pragma solidity ^0.8.10;\npragma experimental ABIEncoderV2;\n\nimport \"./GovernorBravoInterfaces.sol\";\n\ncontract GovernorBr"
},
{
"path": "protocols/compound-v2/src/Governance/GovernorBravoDelegateG2.sol",
"chars": 20856,
"preview": "/*pragma solidity >=0.5.16;\npragma experimental ABIEncoderV2;\n\nimport \"./GovernorBravoInterfaces.sol\";\n\ncontract Governo"
},
{
"path": "protocols/compound-v2/src/Governance/GovernorBravoDelegator.sol",
"chars": 2916,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./GovernorBravoInterfaces.sol\";\n\ncontract Gov"
},
{
"path": "protocols/compound-v2/src/Governance/GovernorBravoInterfaces.sol",
"chars": 7331,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n\ncontract GovernorBravoEvents {\n /// @notice An ev"
},
{
"path": "protocols/compound-v2/src/InterestRateModel.sol",
"chars": 1391,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n/**\n * @title Compound's InterestRateModel Interface"
},
{
"path": "protocols/compound-v2/src/JumpRateModel.sol",
"chars": 4345,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./InterestRateModel.sol\";\n\n/**\n * @title Com"
},
{
"path": "protocols/compound-v2/src/JumpRateModelV2.sol",
"chars": 1069,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./BaseJumpRateModelV2.sol\";\nimport \"./Interes"
},
{
"path": "protocols/compound-v2/src/Lens/CompoundLens.sol",
"chars": 17990,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"../CErc20.sol\";\nimport \"../CToken.sol\";\nimpor"
},
{
"path": "protocols/compound-v2/src/Maximillion.sol",
"chars": 1622,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CEther.sol\";\n\n/**\n * @title Compound's Maxi"
},
{
"path": "protocols/compound-v2/src/PriceOracle.sol",
"chars": 593,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./CToken.sol\";\n\nabstract contract PriceOracle"
},
{
"path": "protocols/compound-v2/src/Reservoir.sol",
"chars": 3018,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n/**\n * @title Reservoir Contract\n * @notice Distribut"
},
{
"path": "protocols/compound-v2/src/SafeMath.sol",
"chars": 6553,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\n// From https://github.com/OpenZeppelin/openzeppelin-"
},
{
"path": "protocols/compound-v2/src/SimplePriceOracle.sol",
"chars": 1629,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./PriceOracle.sol\";\nimport \"./CErc20.sol\";\n\nc"
},
{
"path": "protocols/compound-v2/src/Timelock.sol",
"chars": 4729,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./SafeMath.sol\";\n\ncontract Timelock {\n usi"
},
{
"path": "protocols/compound-v2/src/Unitroller.sol",
"chars": 5696,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./ErrorReporter.sol\";\nimport \"./ComptrollerSt"
},
{
"path": "protocols/compound-v2/src/WhitePaperInterestRateModel.sol",
"chars": 3566,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"./InterestRateModel.sol\";\n\n/**\n * @title Com"
},
{
"path": "protocols/compound-v2/test/core.t.sol",
"chars": 34048,
"preview": "// SPDX-License-Identifier: NONE\npragma solidity ^0.8.10;\n\n// Test Helpers\nimport \"forge-std/Test.sol\";\n\n// Comptroller,"
},
{
"path": "protocols/compound-v2/test/mocks/ERC20.sol",
"chars": 7008,
"preview": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.10;\n\nimport \"../../src/SafeMath.sol\";\n//Taken form compoun"
},
{
"path": "protocols/olympus-v1/.gitignore",
"chars": 10,
"preview": "cache\nout\n"
},
{
"path": "protocols/olympus-v1/.gitmodules",
"chars": 365,
"preview": "[submodule \"lib/forge-std\"]\n\tpath = lib/forge-std\n\turl = https://github.com/foundry-rs/forge-std\n\tbranch = v1.7.1\n[submo"
},
{
"path": "protocols/olympus-v1/LICENSE",
"chars": 34523,
"preview": " GNU AFFERO GENERAL PUBLIC LICENSE\n Version 3, 19 November 2007\n\n Copyright (C)"
},
{
"path": "protocols/olympus-v1/README.md",
"chars": 7405,
"preview": "# Setup\r\n1. `forge install`\r\n2. `forge test --mc TestCore`\r\n\r\n## Integration\r\n1. Follow setup\r\n2. No test helpers needed"
},
{
"path": "protocols/olympus-v1/foundry.toml",
"chars": 161,
"preview": "[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\"]\n\n[fuzz]\nruns = 10000\n\n# See more config options https://github."
},
{
"path": "protocols/olympus-v1/package.json",
"chars": 431,
"preview": "{\n \"name\": \"olympus-contracts\",\n \"version\": \"1.0.0\",\n \"description\": \"Smart Contracts for Olympus\",\n \"directories\": "
},
{
"path": "protocols/olympus-v1/remappings.txt",
"chars": 263,
"preview": "forge-std/=lib/forge-std/src/\n@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts\n@ope"
},
{
"path": "protocols/olympus-v1/script/Counter.s.sol",
"chars": 224,
"preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"forge-std/Script.sol\";\n\ncontract CounterScript "
},
{
"path": "protocols/olympus-v1/src/BondDepository.sol",
"chars": 37442,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\ninterface IOwnable {\n function policy() external "
},
{
"path": "protocols/olympus-v1/src/CVXBondDepository.sol",
"chars": 28586,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\ninterface IOwnable {\n function policy() external "
},
{
"path": "protocols/olympus-v1/src/OlympusERC20.sol",
"chars": 28113,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\nlibrary EnumerableSet {\n\n // To implement this li"
},
{
"path": "protocols/olympus-v1/src/RedeemHelper.sol",
"chars": 2419,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\ninterface IOwnable {\n function policy() external "
},
{
"path": "protocols/olympus-v1/src/RiskFreeValueOfNonReserve.sol",
"chars": 201,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\ncontract RiskFreeValueOfNonReserve {\n function "
},
{
"path": "protocols/olympus-v1/src/Staking.sol",
"chars": 26354,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\nlibrary SafeMath {\n /**\n * @dev Returns the"
},
{
"path": "protocols/olympus-v1/src/StakingDistributor.sol",
"chars": 16964,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity 0.7.5;\n\nlibrary SafeERC20 {\n using SafeMath for uint25"
},
{
"path": "protocols/olympus-v1/src/StakingHelper.sol",
"chars": 3303,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\n\ninterface IERC20 {\n function decimals() extern"
},
{
"path": "protocols/olympus-v1/src/StakingWarmup.sol",
"chars": 3034,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\n\ninterface IERC20 {\n function decimals() extern"
},
{
"path": "protocols/olympus-v1/src/StandardBondingCalculator.sol",
"chars": 9954,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\nlibrary FullMath {\n function fullMul(uint256 x,"
},
{
"path": "protocols/olympus-v1/src/Treasury.sol",
"chars": 25405,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\nlibrary SafeMath {\n\n function add(uint256 a, ui"
},
{
"path": "protocols/olympus-v1/src/mocks/DAI.sol",
"chars": 9310,
"preview": "pragma solidity 0.7.5;\n\n\ncontract LibNote {\n event LogNote(\n bytes4 indexed sig,\n address indexed usr,\n b"
},
{
"path": "protocols/olympus-v1/src/mocks/Frax.sol",
"chars": 8511,
"preview": "// SPDX-License-Identifier: Unlicensed\npragma solidity 0.7.5;\n\n\ncontract LibNote {\n event LogNote(\n bytes4 indexed"
},
{
"path": "protocols/olympus-v1/src/mocks/MockBondDepository.sol",
"chars": 35797,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\ninterface IOwnable {\n function policy() external "
},
{
"path": "protocols/olympus-v1/src/mocks/MockTreasury.sol",
"chars": 23862,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\nlibrary SafeMath {\n function add(uint256 a, uint2"
},
{
"path": "protocols/olympus-v1/src/sOlympusERC20.sol",
"chars": 42187,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\n\n/**\n * @dev Wrappers over Solidity's arithmetic o"
},
{
"path": "protocols/olympus-v1/src/wETHBondDepository.sol",
"chars": 37133,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\npragma solidity 0.7.5;\n\ninterface IOwnable {\n function policy() external "
},
{
"path": "protocols/olympus-v1/src/wOHM.sol",
"chars": 30780,
"preview": "// SPDX-License-Identifier: MIT\npragma solidity 0.7.5;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EI"
},
{
"path": "protocols/olympus-v1/test/IUniswapV2Pair.sol",
"chars": 2424,
"preview": "pragma solidity >=0.5.0;\n\ninterface IUniswapV2Pair {\n event Approval(address indexed owner, address indexed spender, "
},
{
"path": "protocols/olympus-v1/test/core.t.sol",
"chars": 21099,
"preview": "// SPDX-License-Identifier: NONE\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\n// Test Helpers\nimport \"forg"
},
{
"path": "protocols/tombfinance/.gitignore",
"chars": 10,
"preview": "cache\nout\n"
},
{
"path": "protocols/tombfinance/.gitmodules",
"chars": 275,
"preview": "[submodule \"lib/forge-std\"]\n\tpath = lib/forge-std\n\turl = https://github.com/foundry-rs/forge-std\n\tbranch = v1.7.1\n[submo"
},
{
"path": "protocols/tombfinance/README.md",
"chars": 4179,
"preview": "# **Setup**\n# Setup\n1. `forge install`\n2. `forge test --mc TestCore`\n\n## Integration\n1. Follow setup\n2. Add test helpers"
},
{
"path": "protocols/tombfinance/foundry.toml",
"chars": 159,
"preview": "[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\"]\n\n[fuzz]\nruns = 100\n\n# See more config options https://github.co"
},
{
"path": "protocols/tombfinance/remappings.txt",
"chars": 194,
"preview": "forge-std/=lib/forge-std/src/\n@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts\n@solmate/=lib/solmate/src/\n@"
},
{
"path": "protocols/tombfinance/script/Counter.s.sol",
"chars": 224,
"preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"forge-std/Script.sol\";\n\ncontract CounterScript "
},
{
"path": "protocols/tombfinance/src/Distributor.sol",
"chars": 425,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"./interfaces/IDistributor.sol\";\n\ncontract Distributor "
},
{
"path": "protocols/tombfinance/src/DummyToken.sol",
"chars": 774,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol\""
},
{
"path": "protocols/tombfinance/src/Masonry.sol",
"chars": 9116,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimpor"
},
{
"path": "protocols/tombfinance/src/Migrations.sol",
"chars": 413,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.4.22 <0.8.0;\n\ncontract Migrations {\n address public owner;\n u"
},
{
"path": "protocols/tombfinance/src/Oracle.sol",
"chars": 4610,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\n\nimport \"."
},
{
"path": "protocols/tombfinance/src/SimpleERCFund.sol",
"chars": 1067,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.6.0;\n\nimport '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimpor"
},
{
"path": "protocols/tombfinance/src/TBond.sol",
"chars": 1410,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol\""
},
{
"path": "protocols/tombfinance/src/TShare.sol",
"chars": 4310,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@o"
},
{
"path": "protocols/tombfinance/src/TaxOffice.sol",
"chars": 2231,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"./owner/Operator.sol\";\nimport \"./interfaces/ITaxable.s"
},
{
"path": "protocols/tombfinance/src/TaxOfficeV2.sol",
"chars": 6274,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"./"
},
{
"path": "protocols/tombfinance/src/TaxOracle.sol",
"chars": 1902,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"@o"
},
{
"path": "protocols/tombfinance/src/Timelock.sol",
"chars": 6489,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\n/*\n * Copyright 2020 Compound Labs, Inc.\n *\n * Redistribution "
},
{
"path": "protocols/tombfinance/src/Tomb.sol",
"chars": 9991,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol\""
},
{
"path": "protocols/tombfinance/src/Treasury.sol",
"chars": 23020,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/math/Math.sol\";\nimport \"@openz"
},
{
"path": "protocols/tombfinance/src/distribution/TShareRewardPool.sol",
"chars": 10767,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimpor"
},
{
"path": "protocols/tombfinance/src/distribution/TombGenesisRewardPool.sol",
"chars": 11189,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimpor"
},
{
"path": "protocols/tombfinance/src/distribution/TombRewardPool.sol",
"chars": 11437,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimpor"
},
{
"path": "protocols/tombfinance/src/interfaces/IBasisAsset.sol",
"chars": 410,
"preview": "pragma solidity ^0.6.0;\n\ninterface IBasisAsset {\n function mint(address recipient, uint256 amount) external returns ("
},
{
"path": "protocols/tombfinance/src/interfaces/IDecimals.sol",
"chars": 137,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface IDecimals {\n function decimals() external view re"
},
{
"path": "protocols/tombfinance/src/interfaces/IDistributor.sol",
"chars": 88,
"preview": "pragma solidity ^0.6.0;\n\ninterface IDistributor {\n function distribute() external;\n}\n"
},
{
"path": "protocols/tombfinance/src/interfaces/IERC20.sol",
"chars": 2696,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the "
},
{
"path": "protocols/tombfinance/src/interfaces/IMasonry.sol",
"chars": 1026,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface IMasonry {\n function balanceOf(address _mason) ex"
},
{
"path": "protocols/tombfinance/src/interfaces/IOracle.sol",
"chars": 310,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface IOracle {\n function update() external;\n\n funct"
},
{
"path": "protocols/tombfinance/src/interfaces/IShare.sol",
"chars": 197,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface IShare {\n function unclaimedTreasuryFund() extern"
},
{
"path": "protocols/tombfinance/src/interfaces/ISimpleERCFund.sol",
"chars": 304,
"preview": "pragma solidity ^0.6.0;\n\ninterface ISimpleERCFund {\n function deposit(\n address token,\n uint256 amount,"
},
{
"path": "protocols/tombfinance/src/interfaces/ITShareRewardPool.sol",
"chars": 408,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface ITShareRewardPool {\n function deposit(uint256 _pi"
},
{
"path": "protocols/tombfinance/src/interfaces/ITaxable.sol",
"chars": 940,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface ITaxable {\n function setTaxTiersTwap(uint8 _index"
},
{
"path": "protocols/tombfinance/src/interfaces/ITreasury.sol",
"chars": 405,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface ITreasury {\n function epoch() external view retur"
},
{
"path": "protocols/tombfinance/src/interfaces/IUniswapV2Callee.sol",
"chars": 202,
"preview": "pragma solidity ^0.6.0;\n\ninterface IUniswapV2Callee {\n function uniswapV2Call(\n address sender,\n uint25"
},
{
"path": "protocols/tombfinance/src/interfaces/IUniswapV2ERC20.sol",
"chars": 1281,
"preview": "pragma solidity ^0.6.0;\n\ninterface IUniswapV2ERC20 {\n event Approval(address indexed owner, address indexed spender, "
},
{
"path": "protocols/tombfinance/src/interfaces/IUniswapV2Factory.sol",
"chars": 583,
"preview": "pragma solidity ^0.6.0;\n\ninterface IUniswapV2Factory {\n event PairCreated(address indexed token0, address indexed tok"
},
{
"path": "protocols/tombfinance/src/interfaces/IUniswapV2Pair.sol",
"chars": 2673,
"preview": "pragma solidity ^0.6.0;\n\ninterface IUniswapV2Pair {\n event Approval(address indexed owner, address indexed spender, u"
},
{
"path": "protocols/tombfinance/src/interfaces/IUniswapV2Router.sol",
"chars": 4697,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\ninterface IUniswapV2Router {\n function factory() external p"
},
{
"path": "protocols/tombfinance/src/interfaces/IWrappedFtm.sol",
"chars": 247,
"preview": "pragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IWrappedFtm is IERC20 {\n "
},
{
"path": "protocols/tombfinance/src/lib/Babylonian.sol",
"chars": 376,
"preview": "pragma solidity ^0.6.0;\n\nlibrary Babylonian {\n function sqrt(uint256 y) internal pure returns (uint256 z) {\n i"
},
{
"path": "protocols/tombfinance/src/lib/FixedPoint.sol",
"chars": 2795,
"preview": "pragma solidity ^0.6.0;\n\nimport \"./Babylonian.sol\";\n\n// a library for handling binary fixed point numbers (https://en.wi"
},
{
"path": "protocols/tombfinance/src/lib/Safe112.sol",
"chars": 1588,
"preview": "pragma solidity ^0.6.0;\n\nlibrary Safe112 {\n function add(uint112 a, uint112 b) internal pure returns (uint256) {\n "
},
{
"path": "protocols/tombfinance/src/lib/SafeMath8.sol",
"chars": 5146,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations wit"
},
{
"path": "protocols/tombfinance/src/lib/UQ112x112.sol",
"chars": 578,
"preview": "pragma solidity =0.6.12;\n\n// a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_"
},
{
"path": "protocols/tombfinance/src/lib/UniswapV2Library.sol",
"chars": 4902,
"preview": "pragma solidity ^0.6.0;\n\nimport \"@openzeppelin/contracts/math/SafeMath.sol\";\nimport \"../interfaces/IUniswapV2Pair.sol\";\n"
},
{
"path": "protocols/tombfinance/src/lib/UniswapV2OracleLibrary.sol",
"chars": 1703,
"preview": "pragma solidity ^0.6.0;\n\nimport \"./FixedPoint.sol\";\nimport \"../interfaces/IUniswapV2Pair.sol\";\n\n// library with helper m"
},
{
"path": "protocols/tombfinance/src/owner/Operator.sol",
"chars": 1158,
"preview": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.6.12;\n\nimport \"@openzeppelin/contracts/GSN/Context.sol\";\nimport \"@ope"
},
{
"path": "protocols/tombfinance/src/utils/ContractGuard.sol",
"chars": 706,
"preview": "pragma solidity 0.6.12;\n\ncontract ContractGuard {\n mapping(uint256 => mapping(address => bool)) private _status;\n\n "
},
{
"path": "protocols/tombfinance/src/utils/Epoch.sol",
"chars": 2084,
"preview": "pragma solidity ^0.6.0;\n\nimport '@openzeppelin/contracts/math/SafeMath.sol';\n\nimport '../owner/Operator.sol';\n\ncontract "
},
{
"path": "protocols/tombfinance/test/core.t.sol",
"chars": 65543,
"preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.6.0;\npragma experimental ABIEncoderV2;\n\n// Test Helpers\nimpor"
},
{
"path": "protocols/tombfinance/test/mocks/MockUniPair.sol",
"chars": 792,
"preview": "// SPDX-License-Identifier: NONE\npragma solidity ^0.6.2;\n\n// Pair factory and Pair\nimport \"@uni/UniswapV2Factory.sol\";\ni"
},
{
"path": "protocols/tombfinance/test/mocks/MockWeth.sol",
"chars": 2645,
"preview": "\n// Copyright (C) 2015, 2016, 2017 Dapphub\n\n// This program is free software: you can redistribute it and/or modify\n// i"
},
{
"path": "protocols/tombfinance/test/v2-core/UniswapV2ERC20.sol",
"chars": 3714,
"preview": "//pragma solidity =0.5.16;\npragma solidity ^0.6.0;\nimport './interfaces/IUniswapV2ERC20.sol';\nimport './libraries/SafeMa"
},
{
"path": "protocols/tombfinance/test/v2-core/UniswapV2Factory.sol",
"chars": 1964,
"preview": "//pragma solidity =0.5.16;\npragma solidity ^0.6.0;\nimport './interfaces/IUniswapV2Factory.sol';\nimport './UniswapV2Pair."
},
{
"path": "protocols/tombfinance/test/v2-core/UniswapV2Pair.sol",
"chars": 9886,
"preview": "pragma solidity ^0.6.0;\n// pragma solidity =0.5.16;\n\n\nimport './interfaces/IUniswapV2Pair.sol';\nimport './UniswapV2ERC20"
},
{
"path": "protocols/tombfinance/test/v2-core/interfaces/IUniswapV2Callee.sol",
"chars": 185,
"preview": "//pragma solidity >=0.5.0;\npragma solidity >=0.6.0;\ninterface IUniswapV2Callee {\n function uniswapV2Call(address send"
},
{
"path": "protocols/tombfinance/test/v2-core/interfaces/IUniswapV2ERC20.sol",
"chars": 1174,
"preview": "//pragma solidity >=0.5.0;\npragma solidity >=0.6.0;\ninterface IUniswapV2ERC20 {\n event Approval(address indexed owner"
},
{
"path": "protocols/tombfinance/test/v2-core/interfaces/IUniswapV2Factory.sol",
"chars": 689,
"preview": "//pragma solidity >=0.5.0;\npragma solidity >=0.6.0;\ninterface IUniswapV2Factory {\n //event PairCreated(address indexe"
},
{
"path": "protocols/tombfinance/test/v2-core/interfaces/IUniswapV2Pair.sol",
"chars": 2424,
"preview": "pragma solidity >=0.6.0;\n\ninterface IUniswapV2Pair {\n event Approval(address indexed owner, address indexed spender, "
},
{
"path": "protocols/tombfinance/test/v2-core/libraries/Math.sol",
"chars": 628,
"preview": "//pragma solidity =0.5.16;\npragma solidity >=0.6.0;\n// a library for performing various math operations\n\nlibrary Math {\n"
},
{
"path": "protocols/tombfinance/test/v2-core/libraries/SafeMath.sol",
"chars": 589,
"preview": "//pragma solidity =0.5.16;\npragma solidity >=0.6.0;\n// a library for performing overflow-safe math, courtesy of DappHub "
},
{
"path": "protocols/tombfinance/test/v2-core/libraries/UQ112x112.sol",
"chars": 604,
"preview": "//pragma solidity =0.5.16;\npragma solidity >=0.6.0;\n// a library for handling binary fixed point numbers (https://en.wik"
},
{
"path": "protocols/tombfinance/test/v2-core/test/ERC20.sol",
"chars": 212,
"preview": "//pragma solidity =0.5.16;\npragma solidity ^0.6.0;\nimport '../UniswapV2ERC20.sol';\n\ncontract ERC20 is UniswapV2ERC20 {\n "
},
{
"path": "protocols/uniswap-v2/.gitignore",
"chars": 10,
"preview": "cache\nout\n"
},
{
"path": "protocols/uniswap-v2/.gitmodules",
"chars": 275,
"preview": "[submodule \"lib/openzeppelin-contracts\"]\n\tpath = lib/openzeppelin-contracts\n\turl = https://github.com/OpenZeppelin/openz"
},
{
"path": "protocols/uniswap-v2/README.md",
"chars": 3469,
"preview": "# **Setup**\r\n# Setup\r\n1. `forge install OpenZeppelin/openzeppelin-contracts`\r\n2. `forge install foundry-rs/forge-std`\r\n3"
},
{
"path": "protocols/uniswap-v2/foundry.toml",
"chars": 161,
"preview": "[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\"]\n\n[fuzz]\nruns = 10000\n\n# See more config options https://github."
},
{
"path": "protocols/uniswap-v2/remappings.txt",
"chars": 181,
"preview": "forge-std/=lib/forge-std/src/\n@openzeppelin/=lib/openzeppelin-contracts/contracts\n@uniCore/=src/\n@uniPer/=src/contracts\n"
},
{
"path": "protocols/uniswap-v2/script/Counter.s.sol",
"chars": 224,
"preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"forge-std/Script.sol\";\n\ncontract CounterScript "
},
{
"path": "protocols/uniswap-v2/src/UniswapV2ERC20.sol",
"chars": 3638,
"preview": "//pragma solidity =0.5.16;\npragma solidity ^0.8.0;\nimport './interfaces/IUniswapV2ERC20.sol';\nimport './libraries/SafeMa"
},
{
"path": "protocols/uniswap-v2/src/UniswapV2Factory.sol",
"chars": 1896,
"preview": "//pragma solidity =0.5.16;\npragma solidity ^0.8.0;\nimport './interfaces/IUniswapV2Factory.sol';\nimport './UniswapV2Pair."
},
{
"path": "protocols/uniswap-v2/src/UniswapV2Pair.sol",
"chars": 9867,
"preview": "pragma solidity ^0.8.0;\n// pragma solidity =0.5.16;\n\n\nimport './interfaces/IUniswapV2Pair.sol';\nimport './UniswapV2ERC20"
},
{
"path": "protocols/uniswap-v2/src/contracts/UniswapV2Migrator.sol",
"chars": 2306,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\nimport '@uniswap/lib/contracts/libraries/TransferHelper.sol';\n\nimport "
},
{
"path": "protocols/uniswap-v2/src/contracts/UniswapV2Router01.sol",
"chars": 12819,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\nimport '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';\n"
},
{
"path": "protocols/uniswap-v2/src/contracts/UniswapV2Router02.sol",
"chars": 18647,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\nimport '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';\n"
},
{
"path": "protocols/uniswap-v2/src/contracts/examples/ExampleComputeLiquidityValue.sol",
"chars": 2546,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\nimport '../libraries/UniswapV2LiquidityMathLibrary.sol';\n\ncontract Exa"
},
{
"path": "protocols/uniswap-v2/src/contracts/examples/ExampleFlashSwap.sol",
"chars": 3852,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\nimport '@uniswap/v2-core/contracts/interfaces/IUniswapV2Callee.sol';\n\n"
},
{
"path": "protocols/uniswap-v2/src/contracts/examples/ExampleOracleSimple.sol",
"chars": 3193,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\nimport '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';\n"
},
{
"path": "protocols/uniswap-v2/src/contracts/examples/ExampleSlidingWindowOracle.sol",
"chars": 6483,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\nimport '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';\n"
},
{
"path": "protocols/uniswap-v2/src/contracts/examples/ExampleSwapToPrice.sol",
"chars": 2963,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\nimport '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';\nimp"
},
{
"path": "protocols/uniswap-v2/src/contracts/examples/README.md",
"chars": 571,
"preview": "# Examples\n\n## Disclaimer\n\nThese contracts are for demonstrative purposes only.\nWhile these contracts have unit tests, a"
},
{
"path": "protocols/uniswap-v2/src/contracts/interfaces/IUniswapV2Migrator.sol",
"chars": 197,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\ninterface IUniswapV2Migrator {\n function migrate(address token, ui"
},
{
"path": "protocols/uniswap-v2/src/contracts/interfaces/IUniswapV2Router01.sol",
"chars": 3551,
"preview": "//pragma solidity >=0.6.2;\npragma solidity ^0.8.0;\ninterface IUniswapV2Router01 {\n function factory() external view r"
},
{
"path": "protocols/uniswap-v2/src/contracts/interfaces/IUniswapV2Router02.sol",
"chars": 1311,
"preview": "//pragma solidity >=0.6.2;\npragma solidity ^0.8.0;\nimport './IUniswapV2Router01.sol';\n\ninterface IUniswapV2Router02 is I"
},
{
"path": "protocols/uniswap-v2/src/contracts/interfaces/IWETH.sol",
"chars": 221,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\ninterface IWETH {\n function deposit() external payable;\n functi"
},
{
"path": "protocols/uniswap-v2/src/contracts/interfaces/V1/IUniswapV1Exchange.sol",
"chars": 479,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\ninterface IUniswapV1Exchange {\n function balanceOf(address owner) "
},
{
"path": "protocols/uniswap-v2/src/contracts/interfaces/V1/IUniswapV1Factory.sol",
"chars": 150,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\ninterface IUniswapV1Factory {\n function getExchange(address) exter"
},
{
"path": "protocols/uniswap-v2/src/contracts/libraries/UniswapV2Library.sol",
"chars": 4606,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\nimport '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';\n\n/"
},
{
"path": "protocols/uniswap-v2/src/contracts/libraries/UniswapV2LiquidityMathLibrary.sol",
"chars": 6052,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\nimport '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';\nim"
},
{
"path": "protocols/uniswap-v2/src/contracts/libraries/UniswapV2OracleLibrary.sol",
"chars": 1714,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\nimport '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';\nim"
},
{
"path": "protocols/uniswap-v2/src/contracts/test/DeflatingERC20.sol",
"chars": 3771,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\n//import '../libraries/SafeMath.sol';\nimport '@uniCore/libraries/SafeM"
},
{
"path": "protocols/uniswap-v2/src/contracts/test/ERC20.sol",
"chars": 3512,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\n//import '../libraries/SafeMath.sol';\nimport '@uniCore/libraries/SafeM"
},
{
"path": "protocols/uniswap-v2/src/contracts/test/RouterEventEmitter.sol",
"chars": 3216,
"preview": "//pragma solidity =0.6.6;\npragma solidity ^0.8.0;\nimport '../interfaces/IUniswapV2Router01.sol';\n\ncontract RouterEventEm"
},
{
"path": "protocols/uniswap-v2/src/contracts/test/WETH9.sol",
"chars": 37759,
"preview": "// Copyright (C) 2015, 2016, 2017 Dapphub\n\n// This program is free software: you can redistribute it and/or modify\n// it"
},
{
"path": "protocols/uniswap-v2/src/interfaces/IERC20.sol",
"chars": 848,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\ninterface IERC20 {\n event Approval(address indexed owner, address "
},
{
"path": "protocols/uniswap-v2/src/interfaces/IUniswapV2Callee.sol",
"chars": 184,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\ninterface IUniswapV2Callee {\n function uniswapV2Call(address sende"
},
{
"path": "protocols/uniswap-v2/src/interfaces/IUniswapV2ERC20.sol",
"chars": 1173,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\ninterface IUniswapV2ERC20 {\n event Approval(address indexed owner,"
},
{
"path": "protocols/uniswap-v2/src/interfaces/IUniswapV2Factory.sol",
"chars": 688,
"preview": "//pragma solidity >=0.5.0;\npragma solidity ^0.8.0;\ninterface IUniswapV2Factory {\n //event PairCreated(address indexed"
},
{
"path": "protocols/uniswap-v2/src/interfaces/IUniswapV2Pair.sol",
"chars": 2424,
"preview": "pragma solidity >=0.5.0;\n\ninterface IUniswapV2Pair {\n event Approval(address indexed owner, address indexed spender, "
},
{
"path": "protocols/uniswap-v2/src/libraries/AddressStringUtil.sol",
"chars": 1403,
"preview": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.5.0;\n\nlibrary AddressStringUtil {\n // converts an a"
},
{
"path": "protocols/uniswap-v2/src/libraries/Babylonian.sol",
"chars": 561,
"preview": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.4.0;\n\n// computes square roots using the babylonian me"
},
{
"path": "protocols/uniswap-v2/src/libraries/BitMath.sol",
"chars": 844,
"preview": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >=0.5.0;\n\nlibrary BitMath {\n function mostSignificantBit"
},
{
"path": "protocols/uniswap-v2/src/libraries/FixedPoint.sol",
"chars": 5713,
"preview": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >=0.4.0;\n\nimport './FullMath.sol';\nimport './Babylonian.sol"
},
{
"path": "protocols/uniswap-v2/src/libraries/FullMath.sol",
"chars": 3164,
"preview": "// SPDX-License-Identifier: CC-BY-4.0\n//pragma solidity >=0.4.0;\npragma solidity ^0.8.0;\n// USING the EXPENSIVE VERSION "
},
{
"path": "protocols/uniswap-v2/src/libraries/Math.sol",
"chars": 627,
"preview": "//pragma solidity =0.5.16;\npragma solidity ^0.8.0;\n// a library for performing various math operations\n\nlibrary Math {\n "
},
{
"path": "protocols/uniswap-v2/src/libraries/PairNamer.sol",
"chars": 1428,
"preview": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.5.0;\n\nimport './SafeERC20Namer.sol';\n\n// produces name"
},
{
"path": "protocols/uniswap-v2/src/libraries/SafeERC20Namer.sol",
"chars": 3828,
"preview": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity >=0.5.0;\n\nimport './AddressStringUtil.sol';\n\n// produces t"
},
{
"path": "protocols/uniswap-v2/src/libraries/SafeMath.sol",
"chars": 588,
"preview": "//pragma solidity =0.5.16;\npragma solidity ^0.8.0;\n// a library for performing overflow-safe math, courtesy of DappHub ("
},
{
"path": "protocols/uniswap-v2/src/libraries/TransferHelper.sol",
"chars": 1671,
"preview": "// SPDX-License-Identifier: GPL-3.0-or-later\n\n//pragma solidity >=0.6.0;\npragma solidity ^0.8.0;\n// helper methods for i"
},
{
"path": "protocols/uniswap-v2/src/libraries/UQ112x112.sol",
"chars": 603,
"preview": "//pragma solidity =0.5.16;\npragma solidity ^0.8.0;\n// a library for handling binary fixed point numbers (https://en.wiki"
},
{
"path": "protocols/uniswap-v2/src/test/ERC20.sol",
"chars": 216,
"preview": "//pragma solidity =0.5.16;\npragma solidity ^0.8.0;\nimport '../UniswapV2ERC20.sol';\n\ncontract ERC20 is UniswapV2ERC20 {\n "
},
{
"path": "protocols/uniswap-v2/src/test/core.t.sol",
"chars": 43704,
"preview": "// SPDX-License-Identifier: NONE\npragma solidity ^0.8.0;\n\n// Test Helpers, Mock Tokens\nimport \"forge-std/Test.sol\";\nimpo"
},
{
"path": "protocols/uniswap-v2/test/core.t.sol",
"chars": 43737,
"preview": "// SPDX-License-Identifier: NONE\npragma solidity ^0.8.0;\n\n// Test Helpers, Mock Tokens\nimport \"forge-std/Test.sol\";\nimpo"
},
{
"path": "protocols/uniswap-v2/test/mocks/MockToken.sol",
"chars": 507,
"preview": "// SPDX-License-Identifier: NONE\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/token/ERC20/ERC20.sol\";\n\ncontract MockTo"
},
{
"path": "protocols/uniswap-v2/test/mocks/MockWETH.sol",
"chars": 2643,
"preview": "// Copyright (C) 2015, 2016, 2017 Dapphub\n\n// This program is free software: you can redistribute it and/or modify\n// it"
}
]
About this extraction
This page contains the full source code of the 0xNazgul/fuzzydefi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 196 files (1.4 MB), approximately 342.8k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.