chore(certora): add invariant that totalSupply is sumOfBalances

This invariant ensures that the total supply of the used token in the
contract is always greater equal to the sum of all balances within the
token combined.
This commit is contained in:
r4bbit 2024-08-09 09:30:15 +02:00
parent 2e3f775a0d
commit e04f8ae909
1 changed files with 24 additions and 0 deletions

View File

@ -2,12 +2,25 @@ using ERC20A as Token;
methods { methods {
function Token.balanceOf(address) external returns (uint256) envfree; function Token.balanceOf(address) external returns (uint256) envfree;
function Token.totalSupply() external returns (uint256) envfree;
} }
/*-------------------------------------------- /*--------------------------------------------
| Ghosts and hooks | | Ghosts and hooks |
--------------------------------------------*/ --------------------------------------------*/
ghost mathint sumOfBalances {
init_state axiom sumOfBalances == 0;
}
hook Sload uint256 balance Token._balances[KEY address addr] {
require sumOfBalances >= to_mathint(balance);
}
hook Sstore Token._balances[KEY address addr] uint256 newValue (uint256 oldValue) {
sumOfBalances = sumOfBalances - oldValue + newValue;
}
ghost mathint totalReceived; ghost mathint totalReceived;
hook Sload uint256 defaultValue currentContract._marketplaceTotals.received { hook Sload uint256 defaultValue currentContract._marketplaceTotals.received {
@ -28,6 +41,10 @@ hook Sstore currentContract._marketplaceTotals.sent uint256 defaultValue (uint25
totalSent = totalSent + defaultValue - defaultValue_old; totalSent = totalSent + defaultValue - defaultValue_old;
} }
/*--------------------------------------------
| Helper functions |
--------------------------------------------*/
function canCancelRequest(method f) returns bool { function canCancelRequest(method f) returns bool {
return f.selector == sig:withdrawFunds(Marketplace.RequestId).selector; return f.selector == sig:withdrawFunds(Marketplace.RequestId).selector;
} }
@ -45,6 +62,13 @@ function canFailRequest(method f) returns bool {
f.selector == sig:freeSlot(Marketplace.SlotId).selector; f.selector == sig:freeSlot(Marketplace.SlotId).selector;
} }
/*--------------------------------------------
| Invariants |
--------------------------------------------*/
invariant totalSupplyIsSumOfBalances()
to_mathint(Token.totalSupply()) == sumOfBalances;
invariant requestStartedWhenSlotsFilled(env e, Marketplace.RequestId requestId, Marketplace.SlotId slotId) invariant requestStartedWhenSlotsFilled(env e, Marketplace.RequestId requestId, Marketplace.SlotId slotId)
to_mathint(currentContract.requestContext(e, requestId).slotsFilled) == to_mathint(currentContract.getRequest(e, requestId).ask.slots) => currentContract.requestState(e, requestId) == Marketplace.RequestState.Started; to_mathint(currentContract.requestContext(e, requestId).slotsFilled) == to_mathint(currentContract.getRequest(e, requestId).ask.slots) => currentContract.requestState(e, requestId) == Marketplace.RequestState.Started;