Finish ERC20Wrapper

pull/4525/head
ernestognw 2 years ago
parent 8508a6ef53
commit 6769f0b4f5
No known key found for this signature in database
  1. 15
      certora/harnesses/ERC20WrapperHarness.sol
  2. 50
      certora/specs/ERC20Wrapper.spec

@ -2,10 +2,15 @@
pragma solidity ^0.8.20; pragma solidity ^0.8.20;
import "../patched/token/ERC20/extensions/ERC20Wrapper.sol"; import {ERC20Permit} from "../patched/token/ERC20/extensions/ERC20Permit.sol";
import {ERC20Wrapper, IERC20, ERC20} from "../patched/token/ERC20/extensions/ERC20Wrapper.sol";
contract ERC20WrapperHarness is ERC20Wrapper { contract ERC20WrapperHarness is ERC20Permit, ERC20Wrapper {
constructor(IERC20 _underlying, string memory _name, string memory _symbol) ERC20(_name, _symbol) ERC20Wrapper(_underlying) {} constructor(
IERC20 _underlying,
string memory _name,
string memory _symbol
) ERC20(_name, _symbol) ERC20Permit(_name) ERC20Wrapper(_underlying) {}
function underlyingTotalSupply() public view returns (uint256) { function underlyingTotalSupply() public view returns (uint256) {
return underlying().totalSupply(); return underlying().totalSupply();
@ -22,4 +27,8 @@ contract ERC20WrapperHarness is ERC20Wrapper {
function recover(address account) public returns (uint256) { function recover(address account) public returns (uint256) {
return _recover(account); return _recover(account);
} }
function decimals() public view override(ERC20Wrapper, ERC20) returns (uint8) {
return super.decimals();
}
} }

@ -1,18 +1,18 @@
import "helpers/helpers.spec" import "helpers/helpers.spec";
import "ERC20.spec" import "ERC20.spec";
methods { methods {
underlying() returns(address) envfree function underlying() external returns(address) envfree;
underlyingTotalSupply() returns(uint256) envfree function underlyingTotalSupply() external returns(uint256) envfree;
underlyingBalanceOf(address) returns(uint256) envfree function underlyingBalanceOf(address) external returns(uint256) envfree;
underlyingAllowanceToThis(address) returns(uint256) envfree function underlyingAllowanceToThis(address) external returns(uint256) envfree;
depositFor(address, uint256) returns(bool) function depositFor(address, uint256) external returns(bool);
withdrawTo(address, uint256) returns(bool) function withdrawTo(address, uint256) external returns(bool);
recover(address) returns(uint256) function recover(address) external returns(uint256);
} }
use invariant totalSupplyIsSumOfBalances use invariant totalSupplyIsSumOfBalances;
/* /*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
@ -24,7 +24,7 @@ function underlyingBalancesLowerThanUnderlyingSupply(address a) returns bool {
} }
function sumOfUnderlyingBalancesLowerThanUnderlyingSupply(address a, address b) returns bool { function sumOfUnderlyingBalancesLowerThanUnderlyingSupply(address a, address b) returns bool {
return a != b => underlyingBalanceOf(a) + underlyingBalanceOf(b) <= underlyingTotalSupply(); return a != b => underlyingBalanceOf(a) + underlyingBalanceOf(b) <= to_mathint(underlyingTotalSupply());
} }
/* /*
@ -47,7 +47,7 @@ invariant totalSupplyIsSmallerThanUnderlyingBalance()
} }
invariant noSelfWrap() invariant noSelfWrap()
currentContract != underlying() currentContract != underlying();
/* /*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
@ -85,6 +85,7 @@ rule depositFor(env e) {
assert success <=> ( assert success <=> (
sender != currentContract && // invalid sender sender != currentContract && // invalid sender
sender != 0 && // invalid sender sender != 0 && // invalid sender
receiver != currentContract && // invalid receiver
receiver != 0 && // invalid receiver receiver != 0 && // invalid receiver
amount <= senderUnderlyingBalanceBefore && // deposit doesn't exceed balance amount <= senderUnderlyingBalanceBefore && // deposit doesn't exceed balance
amount <= senderUnderlyingAllowanceBefore // deposit doesn't exceed allowance amount <= senderUnderlyingAllowanceBefore // deposit doesn't exceed allowance
@ -92,10 +93,10 @@ rule depositFor(env e) {
// effects // effects
assert success => ( assert success => (
balanceOf(receiver) == balanceBefore + amount && to_mathint(balanceOf(receiver)) == balanceBefore + amount &&
totalSupply() == supplyBefore + amount && to_mathint(totalSupply()) == supplyBefore + amount &&
underlyingBalanceOf(currentContract) == wrapperUnderlyingBalanceBefore + amount && to_mathint(underlyingBalanceOf(currentContract)) == wrapperUnderlyingBalanceBefore + amount &&
underlyingBalanceOf(sender) == senderUnderlyingBalanceBefore - amount to_mathint(underlyingBalanceOf(sender)) == senderUnderlyingBalanceBefore - amount
); );
// no side effect // no side effect
@ -138,16 +139,17 @@ rule withdrawTo(env e) {
// liveness // liveness
assert success <=> ( assert success <=> (
sender != 0 && // invalid sender sender != 0 && // invalid sender
receiver != currentContract && // invalid receiver
receiver != 0 && // invalid receiver receiver != 0 && // invalid receiver
amount <= balanceBefore // withdraw doesn't exceed balance amount <= balanceBefore // withdraw doesn't exceed balance
); );
// effects // effects
assert success => ( assert success => (
balanceOf(sender) == balanceBefore - amount && to_mathint(balanceOf(sender)) == balanceBefore - amount &&
totalSupply() == supplyBefore - amount && to_mathint(totalSupply()) == supplyBefore - amount &&
underlyingBalanceOf(currentContract) == wrapperUnderlyingBalanceBefore - (currentContract != receiver ? amount : 0) && to_mathint(underlyingBalanceOf(currentContract)) == wrapperUnderlyingBalanceBefore - (currentContract != receiver ? amount : 0) &&
underlyingBalanceOf(receiver) == receiverUnderlyingBalanceBefore + (currentContract != receiver ? amount : 0) to_mathint(underlyingBalanceOf(receiver)) == receiverUnderlyingBalanceBefore + (currentContract != receiver ? amount : 0)
); );
// no side effect // no side effect
@ -172,7 +174,7 @@ rule recover(env e) {
requireInvariant totalSupplyIsSumOfBalances; requireInvariant totalSupplyIsSumOfBalances;
requireInvariant totalSupplyIsSmallerThanUnderlyingBalance; requireInvariant totalSupplyIsSmallerThanUnderlyingBalance;
uint256 value = underlyingBalanceOf(currentContract) - totalSupply(); mathint value = underlyingBalanceOf(currentContract) - totalSupply();
uint256 supplyBefore = totalSupply(); uint256 supplyBefore = totalSupply();
uint256 balanceBefore = balanceOf(receiver); uint256 balanceBefore = balanceOf(receiver);
@ -187,8 +189,8 @@ rule recover(env e) {
// effect // effect
assert success => ( assert success => (
balanceOf(receiver) == balanceBefore + value && to_mathint(balanceOf(receiver)) == balanceBefore + value &&
totalSupply() == supplyBefore + value && to_mathint(totalSupply()) == supplyBefore + value &&
totalSupply() == underlyingBalanceOf(currentContract) totalSupply() == underlyingBalanceOf(currentContract)
); );

Loading…
Cancel
Save