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

Fixed Reweight Cadence #96

Merged
merged 1 commit into from
May 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 23 additions & 5 deletions contracts/pcv/EthUniswapPCVController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ import "@openzeppelin/contracts/math/Math.sol";
import "./IUniswapPCVController.sol";
import "../refs/UniRef.sol";
import "../external/UniswapV2Library.sol";
import "../utils/Timed.sol";

/// @title a IUniswapPCVController implementation for ETH
/// @author Fei Protocol
contract EthUniswapPCVController is IUniswapPCVController, UniRef {
contract EthUniswapPCVController is IUniswapPCVController, UniRef, Timed {
using Decimal for Decimal.D256;
using SafeMathCopy for uint256;

uint256 public override reweightWithdrawBPs = 9900;

uint256 internal _reweightDuration = 4 hours;

uint256 internal constant BASIS_POINTS_GRANULARITY = 10000;

/// @notice returns the linked pcv deposit contract
Expand All @@ -40,24 +43,27 @@ contract EthUniswapPCVController is IUniswapPCVController, UniRef {
uint256 _minDistanceForReweightBPs,
address _pair,
address _router
) public UniRef(_core, _pair, _router, _oracle) {
) public UniRef(_core, _pair, _router, _oracle) Timed(_reweightDuration) {
pcvDeposit = IPCVDeposit(_pcvDeposit);

reweightIncentiveAmount = _incentiveAmount;
_minDistanceForReweight = Decimal.ratio(
_minDistanceForReweightBPs,
BASIS_POINTS_GRANULARITY
);

// start timer
_initTimed();
}

receive() external payable {}

/// @notice reweights the linked PCV Deposit to the peg price. Needs to be reweight eligible
function reweight() external override postGenesis whenNotPaused nonContract {
function reweight() external override whenNotPaused {
updateOracle();
require(
reweightEligible(),
"EthUniswapPCVController: Not at incentive parity or not at min distance"
"EthUniswapPCVController: Not passed reweight time or not at min distance"
);
_reweight();
_incentivize();
Expand Down Expand Up @@ -108,12 +114,21 @@ contract EthUniswapPCVController is IUniswapPCVController, UniRef {
emit ReweightMinDistanceUpdate(basisPoints);
}

/// @notice sets the reweight duration
function setDuration(uint256 _duration)
external
override
onlyGovernor
{
_setDuration(_duration);
}

/// @notice signal whether the reweight is available. Must have incentive parity and minimum distance from peg
function reweightEligible() public view override returns (bool) {
bool magnitude =
_getDistanceToPeg().greaterThan(_minDistanceForReweight);
// incentive parity is achieved after a certain time relative to distance from peg
bool time = incentiveContract().isIncentiveParity();
bool time = isTimeEnded();
return magnitude && time;
}

Expand Down Expand Up @@ -146,6 +161,9 @@ contract EthUniswapPCVController is IUniswapPCVController, UniRef {

_burnFeiHeld();

// reset timer
_initTimed();

emit Reweight(msg.sender);
}

Expand Down
2 changes: 2 additions & 0 deletions contracts/pcv/IUniswapPCVController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ interface IUniswapPCVController {

function setPCVDeposit(address _pcvDeposit) external;

function setDuration(uint256 _duration) external;

function setReweightIncentive(uint256 amount) external;

function setReweightMinDistance(uint256 basisPoints) external;
Expand Down
46 changes: 33 additions & 13 deletions test/pcv/EthUniswapPCVController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ const {
expectEvent,
expectRevert,
balance,
time,
expect,
EthUniswapPCVController,
Fei,
MockBot,
MockPCVDeposit,
MockOracle,
MockPair,
Expand Down Expand Up @@ -150,35 +150,55 @@ describe('EthUniswapPCVController', function () {
});
});

describe('From Contract', function() {
it('reverts', async function() {
let bot = await MockBot.new();
await expectRevert(bot.controllerReweight(this.pcvController.address), "CoreRef: Caller is a contract");
describe('Not yet at time', function () {
beforeEach(async function() {
await this.pair.set(100000, 51000000, LIQUIDITY_INCREMENT, {from: userAddress, value: 100000}); // 510:1 FEI/ETH with 10k liquidity
});
});

describe('Not at incentive parity', function () {
it('reverts', async function() {
await this.pair.set(100000, 51000000, LIQUIDITY_INCREMENT, {from: userAddress, value: 100000}); // 510:1 FEI/ETH with 10k liquidity
expect(await this.pcvController.isTimeEnded()).to.be.equal(false);
expect(await this.pcvController.reweightEligible()).to.be.equal(false);
await expectRevert(this.pcvController.reweight(), "EthUniswapPCVController: Not at incentive parity or not at min distance");
await expectRevert(this.pcvController.reweight(), "EthUniswapPCVController: Not passed reweight time or not at min distance");
})

describe('After time period passes', function() {
beforeEach(async function() {
await time.increase(new BN('14400'));
});

it('Reweight eligible', async function() {
expect(await this.pcvController.isTimeEnded()).to.be.equal(true);
expect(await this.pcvController.reweightEligible()).to.be.equal(true);
});

describe('After Reweight', function() {
beforeEach(async function() {
await this.pcvDeposit.deposit(100000, {value: 100000}); // deposit LP
await this.pcvController.reweight({from: userAddress});
});
it('timer resets', async function() {
expect(await this.pcvController.isTimeEnded()).to.be.equal(false);
expect(await this.pcvController.reweightEligible()).to.be.equal(false);
});
});
});
});

describe('Not at min distance', function () {
it('reverts', async function() {
await this.pair.set(100000, 50400000, LIQUIDITY_INCREMENT, {from: userAddress, value: 100000}); // 504:1 FEI/ETH with 10k liquidity
await this.incentive.setIncentiveParity(true);
await time.increase(new BN('14400'));

expect(await this.pcvController.reweightEligible()).to.be.equal(false);
await expectRevert(this.pcvController.reweight(), "EthUniswapPCVController: Not at incentive parity or not at min distance");
await expectRevert(this.pcvController.reweight(), "EthUniswapPCVController: Not passed reweight time or not at min distance");
})
});

describe('No incentive for caller if controller not minter', function() {
beforeEach(async function() {
await this.pair.set(100000, 51000000, LIQUIDITY_INCREMENT, {from: userAddress, value: 100000}); // 510:1 FEI/ETH with 10k liquidity
await this.pcvDeposit.deposit(100000, {value: 100000}); // deposit LP
await this.incentive.setIncentiveParity(true);
await time.increase(new BN('14400'));
expect(await this.pcvController.reweightEligible()).to.be.equal(true);
await this.pcvController.reweight({from: userAddress});
});
Expand All @@ -199,7 +219,7 @@ describe('EthUniswapPCVController', function () {
beforeEach(async function() {
await this.pair.set(100000, 51000000, LIQUIDITY_INCREMENT, {from: userAddress, value: 100000}); // 490:1 FEI/ETH with 10k liquidity
await this.pcvDeposit.deposit(100000, {value: 100000}); // deposit LP
await this.incentive.setIncentiveParity(true);
await time.increase(new BN('14400'));
await this.core.grantMinter(this.pcvController.address, {from: governorAddress});
expect(await this.pcvController.reweightEligible()).to.be.equal(true);
await this.pcvController.reweight({from: userAddress});
Expand Down