Skip to content

Commit

Permalink
chore: last refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
simon-something committed Jan 8, 2025
1 parent c0ffeef commit c0ffeee
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 210 deletions.
26 changes: 8 additions & 18 deletions test/invariant/PROPERTIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,19 @@
| 4 | profile owner can always create a pool |
| 5 | anyone can increase fund in a pool, if strategy (hook) logic allows so and if more than base fee |
| 6 | every deposit/pool creation must take the correct fee on the amount deposited, forwarded to the treasury |
| ACC-1 | Balance sheet is balanced, no bad debt |
| ACC-1 | There is no token which has left the protocol without being accounted for |
| ACC-2 | Each pool is solvable |

The last 2 invariants are general procotol accounting, based on the following balance sheet:
The last 2 invariants are general procotol accounting, one based on the actual overal "cash-flow" and one based on the individual pool accounting.

Protocol balance sheet:
| asset | liabilities |
| ---------------------------------- | ---------------------------------- |
| unallocated tokens in strategies | fund available to allocate |
| (unaccounted tokens in strategies) | tokens allocated but not withdrawn |

The following operations are covered by this accounting
bookholding writings (allocate should be a simple reclassification, kept it as a double-writing for clarity)
- createPool, fundPool: credit: unallocated tokens in strategies, debit: fund available to allocate for a pool
- allocate, batchAllocate: credit: tokens allocated but not withdrawn, debit: unallocated tokens in strategies
- distribute: credit: token sent to recipient, debit: tokens allocated but not withdrawn
- direct transfer to pool: credit: unaccounted tokens in strategies, debit: fund received
- withdraw: credit: token sent to poolOwner, debit: unaccounted tokens in strategies

These 2 are omitted, as they're covered by unit tests:
- direct transfer to protocol contract: credit: tokens in core protocol contract, debit: fund received
- recoverFunds: credit: token send to protocol owner, debit: tokens in core protocol contract
| asset | liabilities |
| ---------------------------------- | ------------------------------------ |
| tokens in strategies | withdrawable tokens (unallocated) |
| (unaccounted tokens in strategies) | tokens to distribute |

Note: Allocation doesn't imply token movement. Instead, it set the *future* balance sheet movements,
which will effectively occur when distributing or withdrawing tokens (accounting wise, it's a requalification of liabilities).

## Other important invariant, covered by the unit tests

Expand Down
4 changes: 1 addition & 3 deletions test/invariant/fuzz/FoundryReproducer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,5 @@ import {FuzzTest} from "./FuzzTest.t.sol";
import {Actors} from "./Setup.t.sol";

contract FoundryReproducer is FuzzTest {
function test_reproduce() public {
assert(true);
}
function test_reproduce() public {}
}
17 changes: 1 addition & 16 deletions test/invariant/fuzz/handlers/HandlerStrategy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,7 @@ contract HandlerStrategy is HandlerAllo {
IAllo.Pool memory _pool = allo.getPool(ghost_poolIds[_poolSeed]);

ERC20(_pool.token).transfer(address(_pool.strategy), _amount);
}

function handler_withdraw(uint256 _poolSeed, uint256 _amount) public {
address _recipient = makeAddr("IAmRecipient");

// Needs at least one pool
if (ghost_poolIds.length == 0) return;

// Get the pool
_poolSeed = _poolSeed % ghost_poolIds.length;
IAllo.Pool memory _pool = allo.getPool(ghost_poolIds[_poolSeed]);

// Withdraw
Actors _actor = _currentActor();
(bool succ,) = _actor.callThroughAnchor(
address(_pool.strategy), 0, abi.encodeCall(BaseStrategy.withdraw, (_pool.token, _amount, _recipient))
);
ghost_totalReceived += _amount;
}
}
4 changes: 1 addition & 3 deletions test/invariant/fuzz/helpers/Actors.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,7 @@ contract Actors is Utils {
contract HandlerActors is Utils, GhostStorage {
function _currentActor() internal view returns (Actors _actor) {
uint256 _seed = uint256(uint160(msg.sender));
_actor = Actors(
payable(_ghost_actors[(_seed % _ghost_actors.length) - 1])
);
_actor = Actors(payable(_ghost_actors[(_seed % _ghost_actors.length)]));
}

function _randomActor(uint256 _seed) internal view returns (Actors _actor) {
Expand Down
4 changes: 1 addition & 3 deletions test/invariant/fuzz/helpers/GhostStorage.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ contract GhostStorage {

mapping(uint256 _poolId => address[] _recipients) ghost_recipients;

uint256 ghost_totalReceived; // only net amounts, after fee (direct transfer)
uint256 ghost_availableToAllocate;
uint256 ghost_totalAllocatedNotDistributed;
uint256 ghost_totalReceived; // only net amounts, after fee (which is directly transfered)
uint256 ghost_totalWithdrawn;

mapping(uint256 _poolId => mapping(address _owner => uint256 _amount)) ghost_allocations;
Expand Down
10 changes: 6 additions & 4 deletions test/invariant/fuzz/helpers/Pools.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,18 @@ contract Pools is Utils, GhostStorage {
//
// Getters
//
event AggregatePoolBalances(uint256);

function _aggregatePoolBalances() internal returns (uint256 _aggregateBalance) {
// Cumulative sum based on the pool internal balances, we're assessing
// its accuracy in a property (avoid "hiding" bad debt in unaccounted
// tokens)
uint256 _totalPoolBalances;
for (uint256 i; i < ghost_poolIds.length; i++) {
uint256 poolId = ghost_poolIds[i];

_totalPoolBalances += IBaseStrategy(allo.getPool(poolId).strategy).getPoolAmount();
IERC20 token = IERC20(allo.getPool(poolId).token);

_totalPoolBalances += token.balanceOf(address(allo.getPool(poolId).strategy));
}
emit AggregatePoolBalances(_totalPoolBalances);
return _totalPoolBalances;
}

Expand Down
1 change: 0 additions & 1 deletion test/invariant/fuzz/properties/PropertiesAllo.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ contract PropertiesAllo is HandlersParent {
);

ghost_totalReceived += _amountAfterFee;
ghost_availableToAllocate += _amountAfterFee;
} else {
// Edge-case of some strategies: only allocation during a defined period
(
Expand Down
Loading

0 comments on commit c0ffeee

Please sign in to comment.