Skip to content

Commit 3e6a492

Browse files
committed
feat: more thourough verification of the transfer lib
1 parent edec6b4 commit 3e6a492

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

certora/harness/TransferHarness.sol

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,29 @@ import "../../src/interfaces/IERC20.sol";
66

77
interface IERC20Extended is IERC20 {
88
function balanceOf(address) external view returns (uint256);
9+
function allowance(address, address) external view returns (uint256);
910
function totalSupply() external view returns (uint256);
1011
}
1112

1213
contract TransferHarness {
1314
using SafeTransferLib for IERC20;
1415

15-
function doTransfer(address token, address from, address to, uint256 value) public {
16+
function doTransferFrom(address token, address from, address to, uint256 value) public {
1617
IERC20(token).safeTransferFrom(from, to, value);
1718
}
1819

20+
function doTransfer(address token, address to, uint256 value) public {
21+
IERC20(token).safeTransfer(to, value);
22+
}
23+
1924
function getBalance(address token, address user) public view returns (uint256) {
2025
return IERC20Extended(token).balanceOf(user);
2126
}
2227

28+
function getAllowance(address token, address owner, address spender) public view returns (uint256) {
29+
return IERC20Extended(token).allowance(owner, spender);
30+
}
31+
2332
function getTotalSupply(address token) public view returns (uint256) {
2433
return IERC20Extended(token).totalSupply();
2534
}

certora/specs/BlueTransfer.spec

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
methods {
2-
function doTransfer(address, address, address, uint256) external envfree;
2+
function doTransfer(address, address, uint256) external envfree;
3+
function doTransferFrom(address, address, address, uint256) external envfree;
34
function getBalance(address, address) external returns (uint256) envfree;
5+
function getAllowance(address, address, address) external returns (uint256) envfree;
46
function getTotalSupply(address) external returns (uint256) envfree;
57

8+
function _.transfer(address, uint256) external => DISPATCHER(true);
69
function _.transferFrom(address, address, uint256) external => DISPATCHER(true);
710
function _.balanceOf(address) external => DISPATCHER(true);
11+
function _.allowance(address, address) external => DISPATCHER(true);
812
function _.totalSupply() external => DISPATCHER(true);
913
}
1014

@@ -22,16 +26,49 @@ function summarySafeTransferFrom(address token, address from, address to, uint25
2226
}
2327
}
2428

25-
rule checkTransfer(address token, address from, address to, uint256 amount) {
26-
require from == currentContract || to == currentContract;
29+
rule checkTransferFromSummary(address token, address from, uint256 amount) {
30+
mathint initialBalance = getBalance(token, currentContract);
31+
require from != currentContract => initialBalance + getBalance(token, from) <= to_mathint(getTotalSupply(token));
32+
33+
doTransferFrom(token, from, currentContract, amount);
34+
mathint finalBalance = getBalance(token, currentContract);
2735

28-
require from != to => getBalance(token, from) + getBalance(token, to) <= to_mathint(getTotalSupply(token));
36+
require myBalances[token] == initialBalance;
37+
summarySafeTransferFrom(token, from, currentContract, amount);
38+
assert myBalances[token] == finalBalance;
39+
}
2940

41+
rule checkTransferSummary(address token, address to, uint256 amount) {
3042
mathint initialBalance = getBalance(token, currentContract);
31-
doTransfer(token, from, to, amount);
43+
require to != currentContract => initialBalance + getBalance(token, to) <= to_mathint(getTotalSupply(token));
44+
45+
doTransfer(token, to, amount);
3246
mathint finalBalance = getBalance(token, currentContract);
3347

3448
require myBalances[token] == initialBalance;
35-
summarySafeTransferFrom(token, from, to, amount);
49+
summarySafeTransferFrom(token, currentContract, to, amount);
3650
assert myBalances[token] == finalBalance;
3751
}
52+
53+
rule transferRevertCondition(address token, address to, uint256 amount) {
54+
uint256 initialBalance = getBalance(token, currentContract);
55+
uint256 toInitialBalance = getBalance(token, to);
56+
require to != currentContract => initialBalance + toInitialBalance <= to_mathint(getTotalSupply(token));
57+
require currentContract != 0 && to != 0;
58+
59+
doTransfer@withrevert(token, to, amount);
60+
61+
assert lastReverted == (initialBalance < amount);
62+
}
63+
64+
rule transferFromRevertCondition(address token, address from, address to, uint256 amount) {
65+
uint256 initialBalance = getBalance(token, from);
66+
uint256 toInitialBalance = getBalance(token, to);
67+
uint256 allowance = getAllowance(token, from, currentContract);
68+
require to != from => initialBalance + toInitialBalance <= to_mathint(getTotalSupply(token));
69+
require from != 0 && to != 0;
70+
71+
doTransferFrom@withrevert(token, from, to, amount);
72+
73+
assert lastReverted == (initialBalance < amount) || allowance < amount;
74+
}

0 commit comments

Comments
 (0)