Skip to content

Commit

Permalink
ERC20 Allocator (volt-protocol#108)
Browse files Browse the repository at this point in the history
* ERC20Allocator, RateLimitedV2, erc20 holding pcv deposit

* fix unit tests

* 2xlarge container to fix failing tests

* lower fuzz runs to reduce memory used

* 2xlarge resource group

* add additional tests for erc20 allocator, add new min check on buffer for dripping

* beef up unit tests, test non whitelisted psms, doAction, edit, delete, deposit, check drip condition, add check effects interaction comments in allocator

* fuzz test getAdjustedAmount

* buffer exhaustion causes dripaction to not be allowed

* add test that sets buffer to 0, which means all condition checks are false

* remove unused _resetBuffer function in RateLimitedV2

* Add tests for RateLimitedV2, mock RateLimitedV2, event for replenishing buffer, fuzz tests for RateLimitedV2

* add fuzz test to both deplete and replenish the buffer

* add comment to rate limited v2 explaining why SSTORE can be saved when already at buffer cap

* VIP-10 solidity and calldata for timelock

* fix bug where drip condition can be true even if pcv deposit has no balance

* increase test coverage for ERC20Allocator with 2 deposits, 1 with decimal normalization, one without, add setup tests

* add more unit test assertions

* refactor allocator to call getSkimDetails, add additional test assertions in decimal normalized unit tests

* add additional assertions on decimals normalizer test

* add additional assertions for getSkimDetails on skim logic in decimal normalizer test

* remove log emit on no-op deposit, change comment from fei to volt

* mainnet roles, integration tests for erc20 allocator

* add skimming integration tests

* remove pesky hardcoded hardhat mainnet block number, vip 10 in typescript and deploy

* remove test looking for log in erc20holding deposit test

* allocator connector feature and tests

* refactor arch to remove default pcv deposit

* fix fialing compound pcv deposit test

* downsize circleci config to large

* lock version pragma on ERC20HoldingPCVDeposit

* lock version pragma on IERC20HoldingPCVDeposit

* update comments for IERC20 allocator

* simplified proposal creation to remove array assignments

* remove address 0 checks, fix issue in check action allowed where buffer was being checked in isolation, rename from target to pcvDeposit, fix tests

* add additional test assertions

* update function and event naming

* fix buffer scaling issue in get drip details function, add more comments and tests

* fix test name, add additional assertions

* remove return value in _depleteBuffer()

* add unit tests where decimals are negative adjusted

* fix typescript proposal

* add example comment to get drip details

* remove unnecessary drip and skim functions that allow passing the psm address, updated tests

* update PSMUpdated event to remove token param

* clean up ts DAO scripts

* update comments in allocator, no code changes

* change view only function in ERC20Allocator from public to external as it was not used inside the contract. Add additional tests to ERC20Allocator, remove console.log from RateLimitedV2

* update buffer cap to 300k, keep 500k per day rate limit per second, fix vip description in typescript

* remove decimal normalizer setter in editPSM, rename editPSM, add to param in skim and drip events, fix tests, add more tests for RateLimitedV2

* fix rate limit buffer

* remove comments from test

* remove chain specific logic for ERC20HoldingPCVDeposit

* add memo to pcv deposit to not use in production, and only use for testing as is

* update names of local variables to be more accurate

* remove check on granting pcv controller role being a whitelisted address in the guardian

* add deployed ERC20 allocator address

* fix bug in integration tests for calculating pcv pre and post proposal

* vip 10 calldata generation matching

* add additional doAction integration tests, add vip10 to erc20 allocator integration tests, add doLogging bool to pre and post timelock verification scripts

* add assertions to vip10
  • Loading branch information
ElliotFriedman authored Sep 13, 2022
1 parent 86868c6 commit eefd60e
Show file tree
Hide file tree
Showing 31 changed files with 3,237 additions and 56 deletions.
4 changes: 4 additions & 0 deletions contracts/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ library Constants {
IWETH public constant WETH =
IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);

/// @notice WETH9 address
IWETH public constant ARBITRUM_WETH =
IWETH(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);

/// @notice USD stand-in address
address public constant USD = 0x1111111111111111111111111111111111111111;

Expand Down
17 changes: 17 additions & 0 deletions contracts/mock/MockPSM.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pragma solidity =0.8.13;

contract MockPSM {
address public underlying;

constructor(address _underlying) {
underlying = _underlying;
}

function setUnderlying(address newUnderlying) external {
underlying = newUnderlying;
}

function balanceReportedIn() external view returns (address) {
return underlying;
}
}
24 changes: 24 additions & 0 deletions contracts/mock/MockRateLimitedV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma solidity =0.8.13;

import "./../utils/RateLimitedV2.sol";
import "./../refs/CoreRef.sol";

contract MockRateLimitedV2 is RateLimitedV2 {
constructor(
address _core,
uint256 _maxRateLimitPerSecond,
uint128 _rateLimitPerSecond,
uint128 _bufferCap
)
RateLimitedV2(_maxRateLimitPerSecond, _rateLimitPerSecond, _bufferCap)
CoreRef(_core)
{}

function depleteBuffer(uint256 amount) public {
_depleteBuffer(amount);
}

function replenishBuffer(uint256 amount) public {
_replenishBuffer(amount);
}
}
106 changes: 106 additions & 0 deletions contracts/pcv/ERC20HoldingPCVDeposit.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity =0.8.13;

import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IWETH} from "@uniswap/v2-periphery/contracts/interfaces/IWETH.sol";
import {CoreRef} from "../refs/CoreRef.sol";
import {PCVDeposit} from "./PCVDeposit.sol";
import {TribeRoles} from "../core/TribeRoles.sol";
import {IPCVDeposit} from "./IPCVDeposit.sol";
import {MainnetAddresses} from "../test/integration/fixtures/MainnetAddresses.sol";
import {ArbitrumAddresses} from "../test/integration/fixtures/ArbitrumAddresses.sol";
import {IERC20HoldingPCVDeposit} from "./IERC20HoldingPCVDeposit.sol";

/// @title ERC20HoldingPCVDeposit
/// @notice PCVDeposit that is used to hold ERC20 tokens as a safe harbour. Deposit is a no-op

/// DO NOT USE in prod, still needs multiple code reviews. Contract is only for testing currently

contract ERC20HoldingPCVDeposit is PCVDeposit, IERC20HoldingPCVDeposit {
using SafeERC20 for IERC20;

/// @notice Token which the balance is reported in
IERC20 public immutable override token;

/// @notice WETH contract
IWETH public immutable weth;

constructor(
address _core,
IERC20 _token,
address _weth
) CoreRef(_core) {
require(
address(_token) != MainnetAddresses.VOLT &&
address(_token) != ArbitrumAddresses.VOLT,
"VOLT not supported"
);
token = _token;
weth = IWETH(_weth);
}

/// @notice Empty receive function to receive ETH
receive() external payable {}

/////// READ-ONLY Methods /////////////

/// @notice returns total balance of PCV in the deposit
function balance() public view override returns (uint256) {
return token.balanceOf(address(this));
}

/// @notice returns the resistant balance and VOLT in the deposit
function resistantBalanceAndVolt()
public
view
override
returns (uint256, uint256)
{
return (balance(), 0);
}

/// @notice display the related token of the balance reported
function balanceReportedIn() public view override returns (address) {
return address(token);
}

/// @notice No-op deposit
function deposit()
external
override(IERC20HoldingPCVDeposit, IPCVDeposit)
whenNotPaused
{}

/// @notice Withdraw underlying
/// @param amountUnderlying of tokens withdrawn
/// @param to the address to send PCV to
function withdraw(address to, uint256 amountUnderlying)
external
override(IERC20HoldingPCVDeposit, IPCVDeposit)
hasAnyOfTwoRoles(TribeRoles.GOVERNOR, TribeRoles.PCV_CONTROLLER)
{
token.safeTransfer(to, amountUnderlying);
emit Withdrawal(msg.sender, to, amountUnderlying);
}

/// @notice Withdraw all of underlying
/// @param to the address to send PCV to
function withdrawAll(address to)
external
hasAnyOfTwoRoles(TribeRoles.GOVERNOR, TribeRoles.PCV_CONTROLLER)
{
uint256 amountUnderlying = token.balanceOf(address(this));
token.safeTransfer(to, amountUnderlying);
emit Withdrawal(msg.sender, to, amountUnderlying);
}

/// @notice Wraps all ETH held by the contract to WETH. Permissionless, anyone can call it
function wrapETH() public {
uint256 ethBalance = address(this).balance;

if (ethBalance != 0) {
weth.deposit{value: ethBalance}();
}
}
}
28 changes: 28 additions & 0 deletions contracts/pcv/IERC20HoldingPCVDeposit.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity =0.8.13;

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

/// @title ERC20HoldingPCVDeposit
/// @notice PCVDeposit that is used to hold ERC20 tokens as a safe harbour. Deposit is a no-op
interface IERC20HoldingPCVDeposit {
/// @notice Token which the balance is reported in
function token() external view returns (IERC20);

/////// READ-ONLY Methods /////////////

/// @notice No-op deposit
function deposit() external;

/// @notice Withdraw underlying
/// @param amountUnderlying of tokens withdrawn
/// @param to the address to send PCV to
function withdraw(address to, uint256 amountUnderlying) external;

/// @notice Withdraw all of underlying
/// @param to the address to send PCV to
function withdrawAll(address to) external;

/// @notice Wraps all ETH held by the contract to WETH. Permissionless, anyone can call it
function wrapETH() external;
}
Loading

0 comments on commit eefd60e

Please sign in to comment.