123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- import "helpers/helpers.spec"
- import "ERC20.spec"
- methods {
- underlying() returns(address) envfree
- underlyingTotalSupply() returns(uint256) envfree
- underlyingBalanceOf(address) returns(uint256) envfree
- underlyingAllowanceToThis(address) returns(uint256) envfree
- depositFor(address, uint256) returns(bool)
- withdrawTo(address, uint256) returns(bool)
- recover(address) returns(uint256)
- }
- use invariant totalSupplyIsSumOfBalances
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Helper: consequence of `totalSupplyIsSumOfBalances` applied to underlying โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- function underlyingBalancesLowerThanUnderlyingSupply(address a) returns bool {
- return underlyingBalanceOf(a) <= underlyingTotalSupply();
- }
- function sumOfUnderlyingBalancesLowerThanUnderlyingSupply(address a, address b) returns bool {
- return a != b => underlyingBalanceOf(a) + underlyingBalanceOf(b) <= underlyingTotalSupply();
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Invariant: wrapped token can't be undercollateralized (solvency of the wrapper) โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- invariant totalSupplyIsSmallerThanUnderlyingBalance()
- totalSupply() <= underlyingBalanceOf(currentContract) &&
- underlyingBalanceOf(currentContract) <= underlyingTotalSupply() &&
- underlyingTotalSupply() <= max_uint256
- {
- preserved {
- requireInvariant totalSupplyIsSumOfBalances;
- require underlyingBalancesLowerThanUnderlyingSupply(currentContract);
- }
- preserved depositFor(address account, uint256 amount) with (env e) {
- require sumOfUnderlyingBalancesLowerThanUnderlyingSupply(e.msg.sender, currentContract);
- }
- }
- invariant noSelfWrap()
- currentContract != underlying()
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: depositFor liveness and effects โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule depositFor(env e) {
- require nonpayable(e);
- address sender = e.msg.sender;
- address receiver;
- address other;
- uint256 amount;
- // sanity
- requireInvariant noSelfWrap;
- requireInvariant totalSupplyIsSumOfBalances;
- requireInvariant totalSupplyIsSmallerThanUnderlyingBalance;
- require sumOfUnderlyingBalancesLowerThanUnderlyingSupply(currentContract, sender);
- uint256 balanceBefore = balanceOf(receiver);
- uint256 supplyBefore = totalSupply();
- uint256 senderUnderlyingBalanceBefore = underlyingBalanceOf(sender);
- uint256 senderUnderlyingAllowanceBefore = underlyingAllowanceToThis(sender);
- uint256 wrapperUnderlyingBalanceBefore = underlyingBalanceOf(currentContract);
- uint256 underlyingSupplyBefore = underlyingTotalSupply();
- uint256 otherBalanceBefore = balanceOf(other);
- uint256 otherUnderlyingBalanceBefore = underlyingBalanceOf(other);
- depositFor@withrevert(e, receiver, amount);
- bool success = !lastReverted;
- // liveness
- assert success <=> (
- sender != currentContract && // invalid sender
- sender != 0 && // invalid sender
- receiver != 0 && // invalid receiver
- amount <= senderUnderlyingBalanceBefore && // deposit doesn't exceed balance
- amount <= senderUnderlyingAllowanceBefore // deposit doesn't exceed allowance
- );
- // effects
- assert success => (
- balanceOf(receiver) == balanceBefore + amount &&
- totalSupply() == supplyBefore + amount &&
- underlyingBalanceOf(currentContract) == wrapperUnderlyingBalanceBefore + amount &&
- underlyingBalanceOf(sender) == senderUnderlyingBalanceBefore - amount
- );
- // no side effect
- assert underlyingTotalSupply() == underlyingSupplyBefore;
- assert balanceOf(other) != otherBalanceBefore => other == receiver;
- assert underlyingBalanceOf(other) != otherUnderlyingBalanceBefore => (other == sender || other == currentContract);
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: withdrawTo liveness and effects โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule withdrawTo(env e) {
- require nonpayable(e);
- address sender = e.msg.sender;
- address receiver;
- address other;
- uint256 amount;
- // sanity
- requireInvariant noSelfWrap;
- requireInvariant totalSupplyIsSumOfBalances;
- requireInvariant totalSupplyIsSmallerThanUnderlyingBalance;
- require sumOfUnderlyingBalancesLowerThanUnderlyingSupply(currentContract, receiver);
- uint256 balanceBefore = balanceOf(sender);
- uint256 supplyBefore = totalSupply();
- uint256 receiverUnderlyingBalanceBefore = underlyingBalanceOf(receiver);
- uint256 wrapperUnderlyingBalanceBefore = underlyingBalanceOf(currentContract);
- uint256 underlyingSupplyBefore = underlyingTotalSupply();
- uint256 otherBalanceBefore = balanceOf(other);
- uint256 otherUnderlyingBalanceBefore = underlyingBalanceOf(other);
- withdrawTo@withrevert(e, receiver, amount);
- bool success = !lastReverted;
- // liveness
- assert success <=> (
- sender != 0 && // invalid sender
- receiver != 0 && // invalid receiver
- amount <= balanceBefore // withdraw doesn't exceed balance
- );
- // effects
- assert success => (
- balanceOf(sender) == balanceBefore - amount &&
- totalSupply() == supplyBefore - amount &&
- underlyingBalanceOf(currentContract) == wrapperUnderlyingBalanceBefore - (currentContract != receiver ? amount : 0) &&
- underlyingBalanceOf(receiver) == receiverUnderlyingBalanceBefore + (currentContract != receiver ? amount : 0)
- );
- // no side effect
- assert underlyingTotalSupply() == underlyingSupplyBefore;
- assert balanceOf(other) != otherBalanceBefore => other == sender;
- assert underlyingBalanceOf(other) != otherUnderlyingBalanceBefore => (other == receiver || other == currentContract);
- }
- /*
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ Rule: recover liveness and effects โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- */
- rule recover(env e) {
- require nonpayable(e);
- address receiver;
- address other;
- // sanity
- requireInvariant noSelfWrap;
- requireInvariant totalSupplyIsSumOfBalances;
- requireInvariant totalSupplyIsSmallerThanUnderlyingBalance;
- uint256 value = underlyingBalanceOf(currentContract) - totalSupply();
- uint256 supplyBefore = totalSupply();
- uint256 balanceBefore = balanceOf(receiver);
- uint256 otherBalanceBefore = balanceOf(other);
- uint256 otherUnderlyingBalanceBefore = underlyingBalanceOf(other);
- recover@withrevert(e, receiver);
- bool success = !lastReverted;
- // liveness
- assert success <=> receiver != 0;
- // effect
- assert success => (
- balanceOf(receiver) == balanceBefore + value &&
- totalSupply() == supplyBefore + value &&
- totalSupply() == underlyingBalanceOf(currentContract)
- );
- // no side effect
- assert underlyingBalanceOf(other) == otherUnderlyingBalanceBefore;
- assert balanceOf(other) != otherBalanceBefore => other == receiver;
- }
|