Skip to content

Commit

Permalink
invariant suite rebased
Browse files Browse the repository at this point in the history
  • Loading branch information
vnmrtz committed May 20, 2024
1 parent edb4d07 commit 14892c9
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 29 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,26 @@ forge test
forge coverage
```

## Invariant Testing Suite

This project has been set up with a suite of tests that check for specific invariants for the reward streams, implemented by [vnmrtz.eth](https://twitter.com/vn_martinez_). These tests are located in the `test/invariants` directory. They are written in Solidity and are designed to be run with the [echidna](https://github.com/crytic/echidna) fuzzing tool.

Installation and usage of these tools is outside the scope of this README, but you can find more information in the respective repositories:
- [Echidna Installation](https://github.com/crytic/echidna)

To run invariant tests with Echidna:

```sh
./test/scripts/echidna.sh
```

To run assert tests with Echidna:

```sh
./test/scripts/echidna-assert.sh
```


## Safety

This software is **experimental** and is provided "as is" and "as available".
Expand Down
17 changes: 17 additions & 0 deletions test/invariants/CryticToFoundry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,23 @@ contract CryticToFoundry is Invariants, Setup {
echidna_UPDATE_REWARDS_INVARIANT();
}

function test_claimSpilloverReward() public {
uint128[] memory rewards = new uint128[](1);
rewards[0] = 2;
this.registerReward(0, 0, rewards);
_delay(4026900 + 204167);
this.claimSpilloverReward(0, 0);
}

function test_DISTRIBUTION_INVARIANTS8() public {
uint128[] memory rewards = new uint128[](1);
rewards[0] = 152;
this.registerReward(0, 0, rewards);
_delay(1800477);
this.claimSpilloverReward(0, 0);
echidna_DISTRIBUTION_INVARIANTS();
}

///////////////////////////////////////////////////////////////////////////////////////////////
// HELPERS //
///////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
23 changes: 7 additions & 16 deletions test/invariants/handlers/BaseRewardsHandler.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {BaseRewardStreamsHarness} from "test/harness/BaseRewardStreamsHarness.so
// Interfaces
import {IRewardStreams} from "src/interfaces/IRewardStreams.sol";

import "forge-std/console.sol";

/// @title BaseRewardsHandler
/// @notice Handler test contract for the risk balance forwarder module actions
contract BaseRewardsHandler is BaseHandler {
Expand Down Expand Up @@ -81,8 +83,9 @@ contract BaseRewardsHandler is BaseHandler {

_before(address(actor), _rewarded, reward);

(success, returnData) =
actor.proxy(_target, abi.encodeWithSelector(IRewardStreams.updateReward.selector, _rewarded, reward));
(success, returnData) = actor.proxy(
_target, abi.encodeWithSelector(IRewardStreams.updateReward.selector, _rewarded, reward, address(0))
);

if (success) {
_after(address(actor), _rewarded, reward);
Expand Down Expand Up @@ -139,12 +142,12 @@ contract BaseRewardsHandler is BaseHandler {
// Get one of the two setups randomly
(address _rewarded, address _target) = _getRandomRewards(j);

uint256 spilloverReward = target.earnedReward(address(0), _rewarded, reward, true);
uint256 spilloverReward = target.earnedReward(address(0), _rewarded, reward, false);

_before(address(actor), _rewarded, reward);

(success, returnData) = actor.proxy(
_target, abi.encodeWithSelector(IRewardStreams.claimSpilloverReward.selector, _rewarded, reward, recipient)
_target, abi.encodeWithSelector(IRewardStreams.updateReward.selector, _rewarded, reward, recipient)
);

if (success) {
Expand Down Expand Up @@ -210,16 +213,4 @@ contract BaseRewardsHandler is BaseHandler {
}
}
}

function assert_VIEW_INVARIANT_A(uint8 i, uint48 epoch, uint48 lastUpdated) external setup {
// Get one of the two setups randomly
(, address _target) = _getRandomRewards(i);

BaseRewardStreamsHarness target_ = BaseRewardStreamsHarness(_target);

try target_.timeElapsedInEpochPublic(epoch, lastUpdated) {}
catch {
assertTrue(false, VIEW_INVARIANT_A);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ contract ERC20BalanceForwarderHandler is BaseHandler {
bool success;
bytes memory returnData;

(success, returnData) = actor.proxy(
address(trackingDistributor), abi.encodeWithSelector(IBalanceForwarder.enableBalanceForwarding.selector)
);
(success, returnData) =
actor.proxy(trackingRewarded, abi.encodeWithSelector(IBalanceForwarder.enableBalanceForwarding.selector));

if (success) {
assert(true);
Expand All @@ -37,9 +36,8 @@ contract ERC20BalanceForwarderHandler is BaseHandler {
bool success;
bytes memory returnData;

(success, returnData) = actor.proxy(
address(trackingDistributor), abi.encodeWithSelector(IBalanceForwarder.disableBalanceForwarding.selector)
);
(success, returnData) =
actor.proxy(trackingRewarded, abi.encodeWithSelector(IBalanceForwarder.disableBalanceForwarding.selector));

if (success) {
assert(true);
Expand All @@ -53,7 +51,7 @@ contract ERC20BalanceForwarderHandler is BaseHandler {
address account = _getRandomActor(i);

(success, returnData) =
actor.proxy(address(trackingDistributor), abi.encodeWithSelector(ERC20.transfer.selector, account, amount));
actor.proxy(trackingRewarded, abi.encodeWithSelector(ERC20.transfer.selector, account, amount));

if (success) {
assert(true);
Expand Down
6 changes: 3 additions & 3 deletions test/invariants/invariants/BaseInvariants.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ abstract contract BaseInvariants is HandlerAggregator {
function assert_BASE_INVARIANT_B(address _rewarded, address _reward, address _target) internal {
(uint256 totalEligible,,) = BaseRewardStreamsHarness(_target).getDistributionTotals(_rewarded, _reward);
if (totalEligible == 0) {
try BaseRewardStreamsHarness(_target).claimSpilloverReward(_rewarded, _reward, address(this)) {}
try BaseRewardStreamsHarness(_target).updateReward(_rewarded, _reward, address(0)) {}
catch {
assertTrue(false, BASE_INVARIANT_B);
}
Expand All @@ -42,8 +42,8 @@ abstract contract BaseInvariants is HandlerAggregator {

function assert_UPDATE_REWARDS_INVARIANT_B(address _rewarded, address _reward, address _target) internal {
BaseRewardStreamsHarness target_ = BaseRewardStreamsHarness(_target);
(uint48 totalEligible,,,,) = target_.getDistributionData(_rewarded, _reward);
assertGe(target_.currentEpoch(), target_.getEpoch(totalEligible), UPDATE_REWARDS_INVARIANT_B);
(uint48 lastUpdated,,,,) = target_.getDistributionData(_rewarded, _reward);
assertGe(target_.currentEpoch(), target_.getEpoch(lastUpdated), UPDATE_REWARDS_INVARIANT_B);
}

function assert_UPDATE_REWARDS_INVARIANT_C(
Expand Down

0 comments on commit 14892c9

Please sign in to comment.