Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VIP-14 Morpho PCV Deposit #128

Merged
merged 88 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
5ba0def
add mock maple contract
ElliotFriedman Oct 2, 2022
344cbc0
Add harvest event to the PCV Deposit Interface
ElliotFriedman Oct 3, 2022
95368fe
Morpho PCV Deposit and integration tests
ElliotFriedman Oct 3, 2022
85e18d2
Maple PCV Deposit, harvest functionality, COMP Token
ElliotFriedman Oct 3, 2022
fc92e6b
Update comment in Compound PCV router to correctly label PCV deposit …
ElliotFriedman Oct 4, 2022
86ea05e
VIP-14 Integration Test Skeleton
ElliotFriedman Oct 4, 2022
43ac3fb
Update TODO PCV Guard Verification
ElliotFriedman Oct 4, 2022
c9ff1b1
VIP-14 Proposal, Deploys Router, Deploys Deposits, Deploys Oracle, Di…
ElliotFriedman Oct 4, 2022
38f7cdb
Add skeleton of VIP-14 integration tests
ElliotFriedman Oct 4, 2022
cf6c21a
VIP-14 typescript implementation
ElliotFriedman Oct 4, 2022
c0ddda9
Morpho router swap integration tests
ElliotFriedman Oct 4, 2022
96c3b93
add arbitrum proposal to set volt price increases to 0
ElliotFriedman Oct 4, 2022
09a11e5
Disable mint tests on arbitrum, pause minting on arbitrum
ElliotFriedman Oct 4, 2022
1b11bda
Pause minting on Arbitrum PSM's
ElliotFriedman Oct 4, 2022
3a927a5
remove newline in mintredeemverification
ElliotFriedman Oct 4, 2022
288fb42
VIP-14 Arbitrum deployment and governance scripts in typescript
ElliotFriedman Oct 4, 2022
6323a8e
remove vm.warp from morpho integration test
ElliotFriedman Oct 5, 2022
f86be20
Morpho and Maple PCV Deposit refactor and integration tests
ElliotFriedman Oct 5, 2022
d72ddea
assertEq
ElliotFriedman Oct 5, 2022
175b45c
add deposit call on maple deposit to vip 14
ElliotFriedman Oct 5, 2022
02453fa
remove arbitrum typescript deployment, arbitrary execution as pcv con…
ElliotFriedman Oct 6, 2022
64177bb
Add pcv deposit pausing
ElliotFriedman Oct 6, 2022
41b1496
update description with deployment steps
ElliotFriedman Oct 6, 2022
513d872
deployment script gov description fix
ElliotFriedman Oct 6, 2022
c231877
Clarifying comments Maple Deposit
ElliotFriedman Oct 6, 2022
72101fa
update maple deposit to accurately track interest and losses
ElliotFriedman Oct 7, 2022
979ce31
update comment
ElliotFriedman Oct 7, 2022
376e7d4
update comment pcv guardian ts
ElliotFriedman Oct 7, 2022
b3a1843
warn comment on maple deposit
ElliotFriedman Oct 7, 2022
101415e
add assertion
ElliotFriedman Oct 7, 2022
729fc01
pause old pcv deposits assertions
ElliotFriedman Oct 7, 2022
64a50dd
Remove new oracle deployment and depositing of pcv into maple
ElliotFriedman Oct 7, 2022
4c0e890
VIP-14 Integration tests
ElliotFriedman Oct 7, 2022
6619e94
typescript proposal update
ElliotFriedman Oct 7, 2022
21d0bf7
Add dev comments to Morpho and Maple PCV Deposits
ElliotFriedman Oct 11, 2022
1ce3129
license
ElliotFriedman Oct 11, 2022
248a693
import visual cleanup
ElliotFriedman Oct 11, 2022
97b9255
PCV Deposit harvest emits amount harvested
ElliotFriedman Oct 13, 2022
3358ab0
Add amount emitted from harvest in deposits
ElliotFriedman Oct 13, 2022
c56434f
attribution to MakerDAO multicall
ElliotFriedman Oct 13, 2022
649ec46
If rewards contract paused, do not stake
ElliotFriedman Oct 17, 2022
6de5056
Morpho 🦋 & Maple 🍁 Slither Run
ElliotFriedman Oct 18, 2022
e83c195
Update contracts/pcv/morpho/ILens.sol
ElliotFriedman Oct 18, 2022
6ca9cc5
Update contracts/pcv/morpho/ILens.sol
ElliotFriedman Oct 18, 2022
4999583
Update comment and constructor params to allow PCV deposit to hold ceth
ElliotFriedman Oct 18, 2022
d2a78e0
Merge branch 'feat/morpho-maple-rate-upgrade' of github.com:volt-prot…
ElliotFriedman Oct 18, 2022
cb8ccd0
fix integration tests and governance proposal
ElliotFriedman Oct 18, 2022
1c06df3
typescript deployment script upgraded to pass 3rd parameter into morp…
ElliotFriedman Oct 18, 2022
79a6981
remove pausing logic from maple smart contracts
ElliotFriedman Oct 18, 2022
91a817b
scalingFactor snakecase, emit withdrawal event in sad path api, add a…
ElliotFriedman Oct 18, 2022
8f6b3d6
remove withdrawAll function from maple pcv deposit
ElliotFriedman Oct 18, 2022
397642b
remove unnecessary cast
ElliotFriedman Oct 18, 2022
28a501a
merge develop and fix merge conflicts
ElliotFriedman Oct 19, 2022
a2fcf0a
remove Maple from PR
ElliotFriedman Oct 19, 2022
49e18cd
typescript vip-14 updates to only handling Morpho deposits
ElliotFriedman Oct 19, 2022
5a03f63
Merge branch 'develop' of github.com:volt-protocol/volt-protocol-core…
ElliotFriedman Oct 19, 2022
1a6b664
Update contracts/pcv/morpho/MorphoCompoundPCVDeposit.sol
ElliotFriedman Oct 19, 2022
a71e3b3
Update contracts/pcv/morpho/MorphoCompoundPCVDeposit.sol
ElliotFriedman Oct 19, 2022
bc52fa4
Update contracts/pcv/morpho/MorphoCompoundPCVDeposit.sol
ElliotFriedman Oct 19, 2022
a96025a
remove revert in mint redeem verification
ElliotFriedman Oct 19, 2022
2073f25
Merge branch 'feat/morpho-maple-rate-upgrade' of github.com:volt-prot…
ElliotFriedman Oct 19, 2022
024edd3
Add profit tracking to Morpho PCV Deposit, fuzz tests, security tests…
ElliotFriedman Oct 20, 2022
3056222
update ts deployment script
ElliotFriedman Oct 20, 2022
457613d
remove console.log
ElliotFriedman Oct 20, 2022
42d92da
update comments on how fast interest accrues at current rates, fix ex…
ElliotFriedman Oct 20, 2022
26be8a2
invariant tests Morpho
ElliotFriedman Oct 20, 2022
81cba10
add additional comments around depositedAmount
ElliotFriedman Oct 20, 2022
0a90a64
invariant tests for morpho compound pcv deposit
ElliotFriedman Oct 20, 2022
ab9c93e
fix unit tests assertions around events being emitted
ElliotFriedman Oct 20, 2022
1fc86aa
add underlying mismatch test
ElliotFriedman Oct 20, 2022
72a4567
slither run 10-21
ElliotFriedman Oct 21, 2022
c8ca5d7
add depositedAmount check equal 0 in recordPNL function
ElliotFriedman Oct 21, 2022
414b443
address Erwan feedback
ElliotFriedman Oct 21, 2022
4d59814
add vip14 to runner, remove vip14a
ElliotFriedman Oct 21, 2022
52f3ef6
change name of depositedAmount to lastRecordedBalance, update tests t…
ElliotFriedman Oct 21, 2022
d1e2632
update comments in MorphoPCVDeposit
ElliotFriedman Oct 21, 2022
513e3a9
add unit test that checks implcit balance check in _withdraw function
ElliotFriedman Oct 21, 2022
9c14d09
organize functions based on type and permission, add large block comm…
ElliotFriedman Oct 21, 2022
072b88d
slither 22 run
ElliotFriedman Oct 22, 2022
a1e9b2f
Add PCV Oracle callback to morpho PCV Deposit
ElliotFriedman Oct 24, 2022
8519129
update deposit endingRecordedBalance to be exact amount pcv deposit o…
ElliotFriedman Oct 24, 2022
d7c9f6c
remove amount == 0 check in _withdraw, setPCVOracle records pnl and u…
ElliotFriedman Oct 24, 2022
ab72cd2
add unit/fuzz tests around calling setPCVOracle
ElliotFriedman Oct 24, 2022
6cd4317
add additional invariant tests for updateLiquidBalance hook
ElliotFriedman Oct 24, 2022
d2c285e
slither run 10/24
ElliotFriedman Oct 25, 2022
7fa0d40
Deploy MorphoCompound PCV Depsosits, add addresses to mainnet address…
ElliotFriedman Oct 25, 2022
0101e8d
remove compound pcv deposits from pcv guard verification
ElliotFriedman Oct 25, 2022
f867262
remove todo comment on adding morpho deposits in pcv guard verification
ElliotFriedman Oct 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions contracts/mock/MockPCVOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pragma solidity 0.8.13;

contract MockPCVOracle {
int256 public pcvAmount;

/// @notice hook on PCV deposit, callable when pcv oracle is set
/// updates the oracle with the new liquid balance delta
function updateLiquidBalance(int256 pcvDelta) external {
pcvAmount += pcvDelta;
}
}
7 changes: 7 additions & 0 deletions contracts/pcv/morpho/IPCVOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pragma solidity 0.8.13;

interface IPCVOracle {
/// @notice hook on PCV deposit, callable when pcv oracle is set
/// updates the oracle with the new liquid balance delta
function updateLiquidBalance(int256 pcvDelta) external;
}
80 changes: 72 additions & 8 deletions contracts/pcv/morpho/MorphoCompoundPCVDeposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {ILens} from "./ILens.sol";
import {IMorpho} from "./IMorpho.sol";
import {CoreRef} from "../../refs/CoreRef.sol";
import {Constants} from "../../Constants.sol";
import {IPCVOracle} from "./IPCVOracle.sol";
import {PCVDeposit} from "../PCVDeposit.sol";
import {ICompoundOracle, ICToken} from "./ICompound.sol";

Expand Down Expand Up @@ -40,6 +41,13 @@ contract MorphoCompoundPCVDeposit is PCVDeposit, ReentrancyGuard {
using SafeERC20 for IERC20;
using SafeCast for *;

/// ------------------------------------------
/// ----------------- Event ------------------
/// ------------------------------------------

/// @notice emitted when the PCV Oracle address is updated
event PCVOracleUpdated(address oldOracle, address newOracle);

/// ------------------------------------------
/// ---------- Immutables/Constant -----------
/// ------------------------------------------
Expand All @@ -62,7 +70,7 @@ contract MorphoCompoundPCVDeposit is PCVDeposit, ReentrancyGuard {
address public immutable cToken;

/// ------------------------------------------
/// ------------- State Variable -------------
/// ------------- State Variables -------------
/// ------------------------------------------

/// @notice track the last amount of PCV recorded in the contract
Expand All @@ -71,6 +79,12 @@ contract MorphoCompoundPCVDeposit is PCVDeposit, ReentrancyGuard {
/// most of the time.
uint256 public lastRecordedBalance;

/// @notice reference to the PCV Oracle. Settable by governance
/// if set, anytime PCV is updated, delta is sent in to update liquid
/// amount of PCV held
/// not set in the constructor
address public pcvOracle;

/// @param _core reference to the core contract
/// @param _cToken cToken this deposit references
/// @param _underlying Token denomination of this deposit
Expand Down Expand Up @@ -131,6 +145,8 @@ contract MorphoCompoundPCVDeposit is PCVDeposit, ReentrancyGuard {
return;
}

int256 startingRecordedBalance = lastRecordedBalance.toInt256();

/// ------ Effects ------

/// compute profit from interest accrued and emit an event
Expand All @@ -151,6 +167,14 @@ contract MorphoCompoundPCVDeposit is PCVDeposit, ReentrancyGuard {
amount
);
ElliotFriedman marked this conversation as resolved.
Show resolved Hide resolved

int256 endingRecordedBalance = balance().toInt256();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not read the state in lastRecordedBalance ? it's freshly updated with _recordPNL() etc

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lastRecordedBalance is off by a hair because on deposit, you take a loss when compound rounds down in favor of their protocol, so you have to read balance instead to get the correct amount of balance in the system.


if (pcvOracle != address(0)) {
IPCVOracle(pcvOracle).updateLiquidBalance(
endingRecordedBalance - startingRecordedBalance
);
}
Comment on lines +172 to +176

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This piece of code is written 4 times and could have been in an internal function

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could refactor this into a helper function, but it's too late in the game to change code before a deployment.


emit Deposit(msg.sender, amount);
}

Expand All @@ -173,8 +197,19 @@ contract MorphoCompoundPCVDeposit is PCVDeposit, ReentrancyGuard {
/// to lastRecordedBalance
/// @return the amount deposited after adding accrued interest or realizing losses
function accrue() external nonReentrant whenNotPaused returns (uint256) {
int256 startingRecordedBalance = lastRecordedBalance.toInt256();

_recordPNL(); /// update deposit amount and fire harvest event

int256 endingRecordedBalance = lastRecordedBalance.toInt256();

if (pcvOracle != address(0)) {
/// if any amount of PCV is withdrawn and no gains, delta is negative
IPCVOracle(pcvOracle).updateLiquidBalance(
endingRecordedBalance - startingRecordedBalance
);
}

return lastRecordedBalance; /// return updated pcv amount
}

Expand All @@ -191,18 +226,54 @@ contract MorphoCompoundPCVDeposit is PCVDeposit, ReentrancyGuard {
onlyPCVController
nonReentrant
{
int256 startingRecordedBalance = lastRecordedBalance.toInt256();

_withdraw(to, amount, true);

int256 endingRecordedBalance = lastRecordedBalance.toInt256();
if (pcvOracle != address(0)) {
/// if any amount of PCV is withdrawn and no gains, delta is negative
IPCVOracle(pcvOracle).updateLiquidBalance(
endingRecordedBalance - startingRecordedBalance
);
}
}

/// @notice withdraw all tokens from Morpho
/// non-reentrant as state changes and external calls are made
/// @param to the address PCV will be sent to
function withdrawAll(address to) external onlyPCVController nonReentrant {
int256 startingRecordedBalance = lastRecordedBalance.toInt256();

/// compute profit from interest accrued and emit an event
_recordPNL();

/// withdraw last recorded amount as this was updated in record pnl
_withdraw(to, lastRecordedBalance, false);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a withdraw all, you also can pass type(uint256).max as argument to avoid leaving dust on Morpho but as you're calling _recordPNL just before it must be exactly the same.

Copy link
Collaborator Author

@ElliotFriedman ElliotFriedman Oct 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing uint256 max to the withdraw function would revert as lastRecordedBalance has amount subtracted from it on line 309. This would cause an underflow and revert.


int256 endingRecordedBalance = lastRecordedBalance.toInt256();

if (pcvOracle != address(0)) {
/// all PCV withdrawn, send call in with amount withdrawn negative if any amount is withdrawn
IPCVOracle(pcvOracle).updateLiquidBalance(
endingRecordedBalance - startingRecordedBalance
);
}
}

/// @notice set the pcv oracle address
/// @param _pcvOracle new pcv oracle to reference
function setPCVOracle(address _pcvOracle) external onlyGovernor {
address oldOracle = pcvOracle;
pcvOracle = _pcvOracle;
ElliotFriedman marked this conversation as resolved.
Show resolved Hide resolved

_recordPNL();

IPCVOracle(pcvOracle).updateLiquidBalance(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can save an sload here by using _pcvOracle instead

lastRecordedBalance.toInt256()
);

emit PCVOracleUpdated(oldOracle, _pcvOracle);
}

/// ------------------------------------------
Expand All @@ -225,13 +296,6 @@ contract MorphoCompoundPCVDeposit is PCVDeposit, ReentrancyGuard {
uint256 amount,
bool recordPnl
) private {
/// ------ Check ------

/// no op if amount to withdraw is 0
if (amount == 0) {
return;
}

/// ------ Effects ------

if (recordPnl) {
ElliotFriedman marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
2 changes: 2 additions & 0 deletions contracts/test/integration/vip/vip14.sol
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ contract vip14 is DSTest, IVIP {
assertEq(address(daiDeposit.core()), core);
assertEq(address(router.core()), core);

assertEq(daiDeposit.pcvOracle(), address(0));
assertEq(usdcDeposit.pcvOracle(), address(0));
assertEq(daiDeposit.morpho(), MainnetAddresses.MORPHO);
assertEq(usdcDeposit.morpho(), MainnetAddresses.MORPHO);
assertEq(daiDeposit.lens(), MainnetAddresses.MORPHO_LENS);
Expand Down
20 changes: 20 additions & 0 deletions contracts/test/invariant/InvariantTestMorphoPCVDeposit.t.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity =0.8.13;

import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import {Vm} from "../unit/utils/Vm.sol";
import {ICore} from "../../core/ICore.sol";
import {DSTest} from "../unit/utils/DSTest.sol";
import {MockERC20} from "../../mock/MockERC20.sol";
import {MockMorpho} from "../../mock/MockMorpho.sol";
import {MockPCVOracle} from "../../mock/MockPCVOracle.sol";
import {DSInvariantTest} from "../unit/utils/DSInvariantTest.sol";
import {MorphoCompoundPCVDeposit} from "../../pcv/morpho/MorphoCompoundPCVDeposit.sol";
import {getCore, getAddresses, VoltTestAddresses} from "../unit/utils/Fixtures.sol";
Expand All @@ -17,13 +19,19 @@ import {getCore, getAddresses, VoltTestAddresses} from "../unit/utils/Fixtures.s

/// @dev Modified from Solmate ERC20 Invariant Test (https://github.com/transmissions11/solmate/blob/main/src/test/ERC20.t.sol)
contract InvariantTestMorphoCompoundPCVDeposit is DSTest, DSInvariantTest {
using SafeCast for *;

MorphoPCVDepositTest public morphoTest;
MockPCVOracle public pcvOracle;
ICore public core;
MorphoCompoundPCVDeposit public morphoDeposit;
MockMorpho public morpho;
MockERC20 public token;
Vm private vm = Vm(HEVM_ADDRESS);
VoltTestAddresses public addresses = getAddresses();

function setUp() public {
pcvOracle = new MockPCVOracle();
core = getCore();
token = new MockERC20();
morpho = new MockMorpho(IERC20(address(token)));
Expand All @@ -36,6 +44,9 @@ contract InvariantTestMorphoCompoundPCVDeposit is DSTest, DSInvariantTest {
);
morphoTest = new MorphoPCVDepositTest(morphoDeposit, token, morpho);

vm.prank(addresses.governorAddress);
morphoDeposit.setPCVOracle(address(pcvOracle));

addTargetContract(address(morphoTest));
}

Expand All @@ -47,6 +58,15 @@ contract InvariantTestMorphoCompoundPCVDeposit is DSTest, DSInvariantTest {
assertEq(morphoDeposit.balance(), morphoTest.totalDeposited());
}

function invariantPcvOracle() public {
assertEq(
morphoDeposit.lastRecordedBalance(),
pcvOracle.pcvAmount().toUint256()
);
assertEq(morphoDeposit.lastRecordedBalance(), morphoDeposit.balance());
assertEq(morphoDeposit.balance(), morphoTest.totalDeposited());
}

function invariantBalanceOf() public {
assertEq(
morphoDeposit.balance(),
Expand Down
Loading