Platform: Code4rena
Start Date: 27/05/2021
End Date: 02/06/2021
Period: 7 days
Status: Completed
Reporters: moneylegobatman, ninek
Pot Size: $100,000 USDC
Participants: 7
Reporters: moneylegobatman, ninek
Judge: LSDan
Id: 12
League: ETH
Yield v2 is a collateralized debt engine paired with a custom automated market maker.
The product offered by Yield v2 is fixed rate borrowing and lending.
All the contracts in this section are to be reviewed. Any contracts not in this list are to be ignored.
The Cast*.sol libraries convert safely between different types.
Fixed point division.
Fixed point division, rounding up.
Fixed point multiplication.
Custom implementation of the ERC20 specifications. Differs from ERC20 standard on when allowances are required and decreased, same as DS-Token.sol.
Extension of ERC20 to accept ERC2612 off-chain approvals.
Produces token descriptors from inconsistent or absent ERC20 symbol implementations that can return string or bytes32
Adapted from Uniswap & BoringSolidity. Safe transferring of ERC20 tokens and Ether, regardless of reverts or return values.
Adapted from Uniswap & BoringSolidity. Safe transferring of ERC20 tokens, regardless of reverts or return values.
String utilities.
Extractor or revert messages from return data.
Access control contract adapted from OpenZeppelin's AccessControl.sol. A role exists for each function in a contract, and if the auth
modifier is present in a function, access must have been granted by the root account. The privileged account can grant and revoke roles, as well as root privileges.
Root can lock functions, disabling any further changes in their access control, except for existing users renouncing to granted roles.
Contract to create a single privileged role that can be held by a single address
Calls Chainlink aggregators to return the value of an asset amount. Two contracts deployed, one for 18 and one for 8 decimals.
Calls Uniswap V3 pools to return the value of an asset amount. One contract deployed.
Calls Compound cTokens to return the borrowing and lending rate. One contract deployed.
Asset holding. Only privileged accounts or contracts can move assets out of the Join, or ask the Join to take assets. Can serve ERC3156 flash loans. One contract per asset deployed.
Deployment of Joins. One contract.
ERC20 zero coupon bond, redeemable at maturity for underlying. Calls Join.sol to obtain funds to serve redemptions, and an Oracle to determine the savings rate, which will be applied to redemptions as well. Can be flash minted with no fees following the ERC3156 standard. Numerous contracts deployed.
Accounting system for Yield v2. The only external dependencies are towards rate oracles and spot oracles. All transactional functions require privileged access. The main function besides accounting is to reveal whether a vault is collateralized using the ink * price * ratio >= art * accrual * rate
formula.
One contract deployed.
Routing and asset management for Yield v2. It has considerable privileges:
Storage variables for Ladle, so that Modules can inherit them and align their storage with the Ladle.
Governance router. The Wand bundles governance calls into governance actions such as adding an asset or a series.
Liquidations engine, same implementation from Yield v1, refactored. Calls the Ladle to move assets, and the Cauldron to obtain and release control of undercollateralized vaults.
ABDK's Math64x64, upgraded to 0.8. Very complex math library, for which only a series of changes were made to use the 0.8 compiler.
YieldSpace AMM curve implementation. Same curve implementation from Yield v1. It was refactored to make the math clearer. Uses Math64x64.sol.
YieldSpace AMM implementation. Refactored from Yield v1, to add a TWAR oracle, single-asset mint and burn, and remove all transferFrom
in favour of keeping track of balances.
Deployment of YieldSpace Pools using CREATE2.
Batching of calls to Pools, along with wrapping/unwrapping of Ether, management of off-chain approvals, and transfers of tokens from users to pools to kickstart transactions.
The Cauldron is the only contract in the Yield Protocol that is not replaceable, and only for that reason any bug in it would be a cause for serious concern.
The Ladle is a complex contract, with wide-ranging powers over the protocol. It is the riskiest contract, and at the same time the one that has more room for a bug to hide. It is of the highest importance to find as many bugs as we can in it.
The mechanism by which the Witch settles debt is not elegant, specifically in using settle
through the Ladle to move assets. It is done this way to avoid governance overhead (and possibility of errors) in giving permission to the Witch to move tokens.
The access control for the Yield Protocol is based on AccessControl.sol, which is a modification of the OpenZeppelin contract of the same name. A bug in this contract would be most likely fatal.
The batching mechanism in Ladle is complex, and therefore risky. So is the vault caching mechanism.
The _mintInternal
function in Pool.sol serves all possible ways of adding liquidity. It is complex, in pathways and in math, and therefore it is an area of concern.
The Math64x64.sol and YieldMath.sol contracts are very complex, but they have been battle tested in Yield v1. For Yield v2 we just refactored them to make them easier to follow, and upgraded them to solidity 0.8. They are not an area of concern, but you are welcome to try to find any bugs in them.
A working instance of the Yield v2 Protocol has been deployed to Kovan for this contest. Feel free to poke around, but if you are going to do something that might have a large impact on the contracts, please do so on a fork so that we don't have to redeploy them. All contracts have been verified on Etherscan.
All the contracts external to Yield have been mocked. In particular, there are mock instances for DAI, USDC, WETH9 and a vanilla ERC20 called TST. These have an open mint
function that anyone can call to receive tokens. There are also mock contracts for what would be Chainlink aggregators and Compound cTokens, used as spot price and rate/chi oracles.
DAI and USDC have been configured as underlying. DAI, USDC, ETH and TST have been configured as collaterals. For each underlying we have deployed two series.
Mocks | Address |
---|---|
DAI | [DAI, '0xA03ae0f02131830d3571dBCD6056BD64939264D0'], |
USDC | [USDC, '0xA48EAd4ad4F29154fD2b1E98f36052547FA1A3Bf'], |
ETH | [ETH, '0xDd848d3DBCFAB61bE5B52A53AB3218F19038eD80'], |
TST | [TST, '0x3e5e276616BD400fFcD6e2333B0d324e0a7D3167'], |
rate source for DAI | [DAI, '0x61382858544B5406B58AEE565D5ba8747902986C'], |
rate source for USDC | [USDC, '0x8c62d6a12b2D4B125240d61554D85C23515a8114'], |
chi source for DAI | [DAI, '0x24331D91d9AF5ba016C34Da73DB7264f290c55Ce'], |
chi source for USDC | [USDC, '0x1F6165Df6e82F4DA9211c1f4861704Ff1De55eBc'], |
spot source for DAI/USDC | [USDC, '0x30bB694F8d6f86b84E12b7b15c8630efA262E6e3'], |
spot source for DAI/ETH | [ETH, '0x50e87B5A48CE4b2aB10014312ea65aE2d649d19B'], |
spot source for DAI/TST | [TST, '0xF1BD9A0AB8C517B590AA39d1C6D46133Baa662df'], |
spot source for USDC/DAI | [DAI, '0x317a9d49f3DbdFb7b76492EAA26156C29D3A8927'], |
spot source for USDC/ETH | [ETH, '0xe99CC1219B927067183e93Ba77bc80a007A76cb6'], |
spot source for USDC/TST | [TST, '0xDa64606a3CB5A4410DF4918Fe35cb89D432A15e6'], |
Protocol | Address |
---|---|
Cauldron | [Cauldron, '0xDA0e6b29405bc6DB9E3414137B716f92a3A23D4e], |
Ladle | [Ladle, '0x6955612C6A972Af16c51764F0756BED8BA504FaB], |
Witch | [Witch, '0x3813A7153D8F46A753928Ddd36c91F085dD30b53], |
Compound MultiOracle | [CompoundMultiOracle, '0xb3AAa9D8EECa58DDb7Ee810EC26B9B8F2815CCcA], |
Chainlink MultiOracle | [ChainlinkMultiOracle, '0xF634dD49Fd6B06B92dFDa4cF70c1F1ed15453269], |
Join Factory | [JoinFactory, '0x59a80F7d9b5e9d93De14140062778a0d5a4Dee22], |
YieldMath | [YieldMath, '0x94578917e07eDc53854b2CEbe57d2818ea69976B'], |
SafeERC20Namer | [SafeERC20Namer, '0xE9AaA1034057Dbf78e6f4366a6792263DA58433F'], |
Pool Factory | [PoolFactory, '0xA554da08CfB85f22fa2a4c7c0A5E7305E7249459'], |
Pool Router | [PoolRouter, '0x0575A2221cb3d524CE105089Eb05BD3C7f685E14'], |
Wand | [Wand, '0x3Cf497A383a4a9D905F76351B9E9620a113eD6E3], |
Joins, FYTokens, Pools | Address |
---|---|
Join for DAI | [DAIJoin, '0xcFe26861baCa98c5a4ECf7923B290894D3aDB208], |
Join for USDC | [USDCJoin, '0x0286Fe190eF0cC0ca10f2E74929c9dC4CC0E61Ef], |
Join for ETH | [ETHJoin, '0x08e5fad1Ce1326c4f75C061494009fE3336A5385], |
Join for TST | [TSTJoin, '0xE343E0b1960A7536749BfDca3eaa866D0d0a953E], |
FYToken DAI1 | [DAI1, '0x189905c0f51Af30aeEd19e4287231a316E77FAd4'], |
FYToken DAI2 | [DAI2, '0xee2dA60685648f2F3D0354dcf59b64FAe08db1B5'], |
FYToken USDC1 | [USDC1, '0x5E08D166092B5fdF281304fCF7D81DD470BF074b'], |
FYToken USDC2 | [USDC2, '0xFC1C50C0eBf217824c379ECB996453074c0ab6Db'], |
Pool for DAI and DAI1 | [DAI1Pool, '0x97412638C270874f9e9fE539e3efAAf49B1d63F7'], |
Pool for DAI and DAI2 | [DAI2Pool, '0x46f41601456EF07e92Fa28d377b62562166F6319'], |
Pool for USDC and USDC1 | [USDC1Pool, '0xa6c8e20D2802a11aCb0faD6273A436A8aDaf8aC9'], |
Pool for USDC and USDC2 | [USDC2Pool, '0x26A0BeD6eFFF9C13eE9564A3153f73Dab028C0f8'], |