Skip to content

Commit

Permalink
Invariant tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wildmolasses committed Feb 21, 2024
1 parent 8db1191 commit 53e0558
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 49 deletions.
31 changes: 18 additions & 13 deletions test/UniStaker.invariants.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ contract UniStakerInvariants is Test {
targetContract(address(handler));
}

// Invariants

function invariant_Sum_of_all_depositor_balances_equals_total_stake() public {
assertEq(uniStaker.totalStaked(), handler.reduceDepositors(0, this.accumulateDeposits));
}

function invariant_Sum_of_beneficiary_earning_power_equals_total_stake() public {
assertEq(uniStaker.totalStaked(), handler.reduceBeneficiaries(0, this.accumulateEarningPower));
}
Expand All @@ -51,11 +57,7 @@ contract UniStakerInvariants is Test {
assertEq(uniStaker.totalStaked(), handler.reduceDelegates(0, this.accumulateSurrogateBalance));
}

function invariant_Sum_of_all_depositor_balances_equals_total_stake() public {
assertEq(uniStaker.totalStaked(), handler.reduceDepositors(0, this.accumulateDeposits));
}

function invariant_Total_staked_minus_withdrawals_equals_total_stake() public {
function invariant_Cumulative_staked_minus_withdrawals_equals_total_stake() public {
assertEq(uniStaker.totalStaked(), handler.ghost_stakeSum() - handler.ghost_stakeWithdrawn());
}

Expand All @@ -66,13 +68,20 @@ contract UniStakerInvariants is Test {
);
}

function invariant_Sum_of_beneficiary_unclaimed_rewards_equals_rewards_left() public {
assertEq(
rewardToken.balanceOf(address(uniStaker)),
handler.reduceBeneficiaries(0, this.accumulateUnclaimedReward)
function invariant_Unclaimed_reward_LTE_total_rewards() public {
assertLe(
handler.reduceBeneficiaries(0, this.accumulateUnclaimedReward),
rewardToken.balanceOf(address(uniStaker))
);
}

// Used to see distribution of non-reverting calls
function invariant_callSummary() public view {
handler.callSummary();
}

// Helpers

function accumulateDeposits(uint256 balance, address depositor) external view returns (uint256) {
return balance + uniStaker.depositorTotalStaked(depositor);
}
Expand Down Expand Up @@ -101,8 +110,4 @@ contract UniStakerInvariants is Test {
address surrogateAddr = address(uniStaker.surrogates(delegate));
return balance + IERC20(address(uniStaker.STAKE_TOKEN())).balanceOf(surrogateAddr);
}

function invariant_callSummary() public view {
handler.callSummary();
}
}
56 changes: 20 additions & 36 deletions test/helpers/UniStaker.handler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,28 @@ import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
contract UniStakerHandler is CommonBase, StdCheats, StdUtils {
using LibAddressSet for AddressSet;

// system setup
UniStaker public uniStaker;
IERC20 public stakeToken;
IERC20 public rewardToken;
address public admin;

uint256 public ghost_stakeSum;
uint256 public ghost_stakeWithdrawn;
uint256 public ghost_depositCount;
uint256 public ghost_rewardsClaimed;
uint256 public ghost_rewardsNotified;

mapping(bytes32 => uint256) public calls;

// actors, deposit state
address internal currentActor;

AddressSet internal _depositors;
AddressSet internal _delegates;
AddressSet internal _beneficiaries;
AddressSet internal _surrogates;
AddressSet internal _rewardNotifiers;

mapping(address => uint256[]) internal _depositIds;
mapping(bytes32 => uint256) public calls;

function _getActorRandDepositId(uint256 _randomDepositSeed) internal view returns (uint256) {
return _depositIds[currentActor][_randomDepositSeed % _depositIds[currentActor].length];
}

function _createDepositor() internal {
currentActor = msg.sender;
// Surrogates can't stake. We won't include them as potential depositors.
vm.assume(!_surrogates.contains(currentActor));
_depositors.add(msg.sender);
}

function _useActor(AddressSet storage _set, uint256 _randomActorSeed) internal {
currentActor = _set.rand(_randomActorSeed);
}
// ghost vars
uint256 public ghost_stakeSum;
uint256 public ghost_stakeWithdrawn;
uint256 public ghost_depositCount;
uint256 public ghost_rewardsClaimed;
uint256 public ghost_rewardsNotified;

modifier countCall(bytes32 key) {
calls[key]++;
Expand Down Expand Up @@ -101,10 +86,6 @@ contract UniStakerHandler is CommonBase, StdCheats, StdUtils {
{
_createDepositor();

// TODO: decide if we want reverts in stake
//_beneficiary = address(uint160(bound(uint160(_beneficiary), 1, type(uint160).max)));
//_delegatee = address(uint160(bound(uint160(_delegatee), 1, type(uint160).max)));

_beneficiaries.add(_beneficiary);
_delegates.add(_delegatee);
// todo: adjust upper bound
Expand Down Expand Up @@ -175,12 +156,19 @@ contract UniStakerHandler is CommonBase, StdCheats, StdUtils {
skip(_seconds);
}

function _getBeneficiaryEarningPower(address _beneficiary) internal view returns (uint256) {
return uniStaker.earningPower(_beneficiary);
function _getActorRandDepositId(uint256 _randomDepositSeed) internal view returns (uint256) {
return _depositIds[currentActor][_randomDepositSeed % _depositIds[currentActor].length];
}

function _createDepositor() internal {
currentActor = msg.sender;
// Surrogates can't stake. We won't include them as potential depositors.
vm.assume(!_surrogates.contains(currentActor));
_depositors.add(msg.sender);
}

function forEachActor(function(address) external func) public {
return _depositors.forEach(func);
function _useActor(AddressSet storage _set, uint256 _randomActorSeed) internal {
currentActor = _set.rand(_randomActorSeed);
}

function reduceDepositors(uint256 acc, function(uint256,address) external returns (uint256) func)
Expand All @@ -204,10 +192,6 @@ contract UniStakerHandler is CommonBase, StdCheats, StdUtils {
return _delegates.reduce(acc, func);
}

function actors() external view returns (address[] memory) {
return _depositors.addrs;
}

function callSummary() external view {
console.log("\nCall summary:");
console.log("-------------------");
Expand Down

0 comments on commit 53e0558

Please sign in to comment.