Skip to content

Commit

Permalink
Merge pull request #1031 from fei-protocol/ops-lbp-withdraw
Browse files Browse the repository at this point in the history
TIP_121a (continued): Protocol ops and LBP withdraw
  • Loading branch information
Joeysantoro authored Sep 5, 2022
2 parents 0fb10e1 + 2815faa commit b2d2268
Show file tree
Hide file tree
Showing 14 changed files with 334 additions and 127 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
e2e-test:
working_directory: ~/repo
executor: nodeimage
parallelism: 13
parallelism: 12
steps:
- attach_workspace:
at: ./
Expand Down
2 changes: 1 addition & 1 deletion block.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
15417090
15460946
98 changes: 0 additions & 98 deletions contracts/test/integration/pcv/AngleEuroRedeemer.sol

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {DSTest} from "../../utils/DSTest.sol";
import {StdLib} from "../../utils/StdLib.sol";
import {Vm} from "../../utils/Vm.sol";
import {MainnetAddresses} from "../fixtures/MainnetAddresses.sol";
import {Fei} from "../../../fei/Fei.sol";

import "../../../sentinel/PCVSentinel.sol";
import "../../../sentinel/guards/MaxFeiWithdrawalGuard.sol";
Expand Down Expand Up @@ -46,6 +47,25 @@ contract MaxFeiWithdrawalGuardIntegrationTest is DSTest, StdLib {

vm.prank(MainnetAddresses.FEI_DAO_TIMELOCK);
sentinel.knight(address(guard));

// Test assumes withdraw amount greater than liquidity
// Mint and remove liquidity to set that up
vm.startPrank(MainnetAddresses.FEI_DAO_TIMELOCK);

Fei(MainnetAddresses.FEI).mint(deposit1, 500_000e18);
IPCVDeposit(deposit1).deposit();

Fei(MainnetAddresses.FEI).mint(deposit2, 500_000e18);
IPCVDeposit(deposit2).deposit();
vm.stopPrank();

uint256 source1Burn = fei.balanceOf(liquiditySource1) - 1000e18;
vm.prank(liquiditySource1);
Fei(MainnetAddresses.FEI).burn(source1Burn);

uint256 source2Burn = fei.balanceOf(liquiditySource2) - 1000e18;
vm.prank(liquiditySource2);
Fei(MainnetAddresses.FEI).burn(source2Burn);
}

function testGuardCanProtec() public {
Expand Down
File renamed without changes.
File renamed without changes.
146 changes: 146 additions & 0 deletions proposals/dao/tip_121b.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import hre, { ethers, artifacts } from 'hardhat';
import { expect } from 'chai';
import {
DeployUpgradeFunc,
NamedAddresses,
PcvStats,
SetupUpgradeFunc,
TeardownUpgradeFunc,
ValidateUpgradeFunc
} from '@custom-types/types';
import { BigNumber } from 'ethers';

/*
TIP_121b: Protocol ops and technical cleanup
*/

const toBN = ethers.BigNumber.from;

const fipNumber = 'tip_121b';

// FEI balance on the TC timelock
const TC_FEI_BALANCE = '2733169815107120096987175';

// TRIBE balance on the TC timelock
const TC_TRIBE_BALANCE = '2733170474316903966022879';

// LBP swapper fund limits
const MIN_LUSD_SWAP_LUSD = ethers.constants.WeiPerEther.mul(230_000);
const MIN_LUSD_SWAP_DAI = ethers.constants.WeiPerEther.mul(17_000_000);

const MIN_WETH_SWAP_WETH = ethers.constants.WeiPerEther.mul(900);
const MIN_WETH_SWAP_DAI = ethers.constants.WeiPerEther.mul(32_000_000);

// STETH Price bounds
const STETH_UPPER_PRICE = ethers.constants.WeiPerEther.mul(1_900); // $1900
const STETH_LOWER_PRICE = ethers.constants.WeiPerEther.mul(1_100); // $1100

// PCV equity diff bounds
const PCV_DIFF_UPPER = ethers.constants.WeiPerEther.mul(1_000_000);
const PCV_DIFF_LOWER = ethers.constants.WeiPerEther.mul(-6_000_000);

let pcvStatsBefore: PcvStats;
let initialFeiSupply: BigNumber;
let initialTCTribeBalance: BigNumber;
let initialDaiBalance: BigNumber;
let initialStethBalance: BigNumber;

// Do any deployments
// This should exclusively include new contract deployments
const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => {
console.log(`No deploy actions for fip${fipNumber}`);
return {
// put returned contract objects here
};
};

// Do any setup necessary for running the test.
// This could include setting up Hardhat to impersonate accounts,
// ensuring contracts have a specific state, etc.
const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => {
pcvStatsBefore = await contracts.collateralizationOracle.pcvStats();
initialFeiSupply = await contracts.fei.totalSupply();
initialTCTribeBalance = await contracts.tribe.balanceOf(addresses.core);
initialDaiBalance = await contracts.daiHoldingPCVDeposit.balance();
initialStethBalance = await contracts.ethLidoPCVDeposit.balance();
};

// Tears down any changes made in setup() that need to be
// cleaned up before doing any validation checks.
const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => {
console.log(`No actions to complete in teardown for fip${fipNumber}`);
};

// Run any validations required on the fip using mocha or console logging
// IE check balances, check state of contracts, etc.
const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => {
// 0. Verify PCV has minimal change
console.log('----------------------------------------------------');
console.log(' pcvStatsBefore.protocolControlledValue [M]e18 ', Number(pcvStatsBefore.protocolControlledValue) / 1e24);
console.log(' pcvStatsBefore.userCirculatingFei [M]e18 ', Number(pcvStatsBefore.userCirculatingFei) / 1e24);
console.log(' pcvStatsBefore.protocolEquity [M]e18 ', Number(pcvStatsBefore.protocolEquity) / 1e24);
const pcvStatsAfter: PcvStats = await contracts.collateralizationOracle.pcvStats();
console.log('----------------------------------------------------');
console.log(' pcvStatsAfter.protocolControlledValue [M]e18 ', Number(pcvStatsAfter.protocolControlledValue) / 1e24);
console.log(' pcvStatsAfter.userCirculatingFei [M]e18 ', Number(pcvStatsAfter.userCirculatingFei) / 1e24);
console.log(' pcvStatsAfter.protocolEquity [M]e18 ', Number(pcvStatsAfter.protocolEquity) / 1e24);
console.log('----------------------------------------------------');
const pcvDiff = pcvStatsAfter.protocolControlledValue.sub(pcvStatsBefore.protocolControlledValue);
const cFeiDiff = pcvStatsAfter.userCirculatingFei.sub(pcvStatsBefore.userCirculatingFei);
const eqDiff = pcvStatsAfter.protocolEquity.sub(pcvStatsBefore.protocolEquity);
console.log(' PCV diff [M]e18 ', Number(pcvDiff) / 1e24);
console.log(' Circ FEI diff [M]e18 ', Number(cFeiDiff) / 1e24);
console.log(' Equity diff [M]e18 ', Number(eqDiff) / 1e24);
console.log('----------------------------------------------------');

expect(eqDiff).to.be.bignumber.greaterThan(PCV_DIFF_LOWER);
expect(eqDiff).to.be.bignumber.lessThan(PCV_DIFF_UPPER);

// 1. Verify FEI burned as expected
const feiSupplyDiff = initialFeiSupply.sub(await contracts.fei.totalSupply());
expect(feiSupplyDiff).to.equal(TC_FEI_BALANCE);

// 2. Verify TRIBE sent to DAO treasury
const tcTribeBalanceDiff = (await contracts.tribe.balanceOf(addresses.core)).sub(initialTCTribeBalance);
expect(tcTribeBalanceDiff).to.equal(TC_TRIBE_BALANCE);

// 3. Verify TC has no funds
expect(await contracts.fei.balanceOf(addresses.tribalCouncilTimelock)).to.equal(0);
expect(await contracts.tribe.balanceOf(addresses.tribalCouncilTimelock)).to.equal(0);

// 4. Verify no FEI on DAO timelock
expect(await contracts.fei.balanceOf(addresses.feiDAOTimelock)).to.equal(0);

// 5. Verify all LUSD, WETH and DAI moved out of LBP swappers
// Verify nothing left on swappers
expect(await contracts.dai.balanceOf(addresses.lusdToDaiSwapper)).to.equal(0);
expect(await contracts.lusd.balanceOf(addresses.lusdToDaiSwapper)).to.equal(0);

expect(await contracts.weth.balanceOf(addresses.ethToDaiLBPSwapper)).to.equal(0);
expect(await contracts.dai.balanceOf(addresses.ethToDaiLBPSwapper)).to.equal(0);

// Verify LUSD Holding
expect(await contracts.lusd.balanceOf(addresses.lusdHoldingPCVDeposit)).to.bignumber.greaterThan(MIN_LUSD_SWAP_LUSD);

// Verify WETH Holding (converted to Lido stETH)
const stethBalanceAfter = await contracts.ethLidoPCVDeposit.balance();
expect(stethBalanceAfter.sub(initialStethBalance)).to.be.bignumber.greaterThan(MIN_WETH_SWAP_WETH);

// Verify swapped tokens ended up at destinations correctly
expect(await contracts.dai.balanceOf(addresses.daiHoldingPCVDeposit)).to.be.bignumber.greaterThan(
initialDaiBalance.add(MIN_LUSD_SWAP_DAI.add(MIN_WETH_SWAP_DAI)) // DAI from WETH and LUSD swaps
);

// 6. Verify stETH oracle set on CR
expect(await contracts.collateralizationOracle.tokenToOracle(addresses.weth)).to.equal(
addresses.chainlinkStEthUsdOracleWrapper
);
// 7. Verify stETH oracle reports a reasonable price
const stETHUSDPrice = (await contracts.chainlinkStEthUsdOracleWrapper.read())[0].toString();
expect(toBN(stETHUSDPrice)).to.be.bignumber.greaterThan(STETH_LOWER_PRICE);
expect(toBN(stETHUSDPrice)).to.be.bignumber.lessThan(STETH_UPPER_PRICE);
};

export { deploy, setup, teardown, validate };
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit b2d2268

Please sign in to comment.