Skip to content

Commit ac17d12

Browse files
Merge pull request #3 from solidity-labs-io/feat/final-stretch
checkpoint
2 parents ccc8768 + de14ed7 commit ac17d12

File tree

10 files changed

+432
-110
lines changed

10 files changed

+432
-110
lines changed

README.md

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,6 @@ This workshop will walk you through the basics of securing smart contracts by te
66

77
In this workshop we will be protecting a governance heavy application from the consequences of malicious upgrades and or deployment scripts.
88

9-
## Bug Types
10-
- **Deployment** - Incorrect parameters, caught with a validation
11-
- **Deployment** - Incorrect parameters, caught with an integration test ✓
12-
****
13-
- **Upgrade** - Storage offset changes, caught with an integration test, also caught with a validation
14-
- **Upgrade** - Logic error, caught with an integration test
15-
****
16-
179
### Further Reading
1810

1911
For governance safety assistance, refer to our [forge proposal simulator](https://github.com/solidity-labs-io/forge-proposal-simulator) tool. See the [security checklist](https://github.com/solidity-labs-io/code-review-checklist) and [security](https://medium.com/@elliotfriedman3/a-security-stack-4aedd8617e8b) [stack](https://medium.com/@elliotfriedman3/a-security-stack-part-2-aaacbbf77346) for a list of items to consider when building a smart contract system.
@@ -31,11 +23,3 @@ Make sure the latest version of foundry is installed. If not, run:
3123
```bash
3224
foundryup
3325
```
34-
35-
Later exercises will use the certora prover. If you need to install, first check the system prerequisites from the Certora documentation. https://docs.certora.com/en/latest/docs/user-guide/install.html
36-
37-
To install the prover run:
38-
39-
```bash
40-
pip3 install certora-cli
41-
```
File renamed without changes.

src/exercises/03/Vault03.sol

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {VaultStorageOwnable} from
1010
"src/exercises/storage/VaultStorageOwnable.sol";
1111

1212
/// @notice Add maxsupply to the vault and update getNormalizedAmount logic
13-
/// deploy Vault 03 to mainnet
1413
/// add integration tests
1514
contract Vault is VaultStorageOwnable {
1615
using SafeERC20 for IERC20;
@@ -180,7 +179,7 @@ contract Vault is VaultStorageOwnable {
180179
uint8 decimals = IERC20Metadata(token).decimals();
181180
normalizedAmount = amount;
182181
if (decimals < 18) {
183-
normalizedAmount = amount ** (10 * (18 - decimals));
182+
normalizedAmount = amount * (10 ** (18 - decimals));
184183
}
185184
}
186185
}

src/exercises/04/SIP04.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ contract SIP04 is GovernorBravoProposal {
7070
override
7171
buildModifier(addresses.getAddress("COMPOUND_TIMELOCK_BRAVO"))
7272
{
73+
/// static calls - filtered out
7374
address vaultProxy = addresses.getAddress("VAULT_PROXY");
7475
bytes32 adminSlot =
7576
vm.load(vaultProxy, ERC1967Utils.ADMIN_SLOT);
@@ -115,6 +116,9 @@ contract SIP04 is GovernorBravoProposal {
115116
vm.load(vaultProxy, ERC1967Utils.ADMIN_SLOT);
116117
address proxyAdmin = address(uint160(uint256(adminSlot)));
117118

119+
/// check not paused
120+
/// check logic contract address is v4 impl
121+
118122
assertEq(
119123
ProxyAdmin(proxyAdmin).owner(),
120124
addresses.getAddress("COMPOUND_TIMELOCK_BRAVO"),

src/exercises/storage/VaultStoragePausable.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {Authorized} from "src/exercises/storage/Authorized.sol";
1212
contract VaultStoragePausable is
1313
OwnableUpgradeable,
1414
Supply,
15+
Authorized,
1516
Balances,
16-
PausableUpgradeable,
17-
Authorized
17+
PausableUpgradeable
1818
{}

src/proposals/sips/sips.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

test/TestVault01.t.sol

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
pragma solidity ^0.8.0;
2+
3+
import {SafeERC20} from
4+
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
5+
import {console} from "@forge-std/console.sol";
6+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7+
import {Test} from "@forge-std/Test.sol";
8+
9+
import {Vault} from "src/exercises/01/Vault01.sol";
10+
import {SIP01} from "src/exercises/01/SIP01.sol";
11+
12+
contract TestVault01 is Test, SIP01 {
13+
using SafeERC20 for IERC20;
14+
15+
Vault public vault;
16+
17+
/// @notice user addresses
18+
address public immutable userA = address(1111);
19+
address public immutable userB = address(2222);
20+
address public immutable userC = address(3333);
21+
22+
/// @notice token addresses
23+
address public usdc;
24+
address public usdt;
25+
26+
function setUp() public {
27+
/// set the environment variables
28+
vm.setEnv("DO_RUN", "false");
29+
vm.setEnv("DO_BUILD", "false");
30+
vm.setEnv("DO_DEPLOY", "true");
31+
vm.setEnv("DO_SIMULATE", "false");
32+
vm.setEnv("DO_PRINT", "false");
33+
vm.setEnv("DO_VALIDATE", "true");
34+
35+
/// setup the proposal
36+
setupProposal();
37+
38+
/// run the proposal
39+
deploy();
40+
41+
usdc = addresses.getAddress("USDC");
42+
usdt = addresses.getAddress("USDT");
43+
vault = Vault(addresses.getAddress("V1_VAULT"));
44+
}
45+
46+
function testVaultDepositUsdc() public {
47+
uint256 usdcDepositAmount = 1_000e6;
48+
49+
_vaultDeposit(usdc, address(this), usdcDepositAmount);
50+
}
51+
52+
function testMultipleUsersDepositUsdc() public {
53+
uint256 usdcDepositAmount = 1_000e6;
54+
55+
_vaultDeposit(usdc, userA, usdcDepositAmount);
56+
_vaultDeposit(usdc, userB, usdcDepositAmount);
57+
_vaultDeposit(usdc, userC, usdcDepositAmount);
58+
}
59+
60+
function testVaultWithdrawalUsdc() public {
61+
uint256 usdcDepositAmount = 1_000e6;
62+
63+
_vaultDeposit(usdc, address(this), usdcDepositAmount);
64+
65+
vault.withdraw(usdc, usdcDepositAmount);
66+
67+
assertEq(
68+
vault.balanceOf(address(this)),
69+
0,
70+
"vault usdc balance not 0"
71+
);
72+
assertEq(
73+
vault.totalSupplied(), 0, "vault total supplied not 0"
74+
);
75+
assertEq(
76+
IERC20(usdc).balanceOf(address(this)),
77+
usdcDepositAmount,
78+
"user's usdc balance not increased"
79+
);
80+
}
81+
82+
function testVaultDepositUsdt() public {
83+
uint256 usdtDepositAmount = 1_000e8;
84+
85+
_vaultDeposit(usdt, address(this), usdtDepositAmount);
86+
}
87+
88+
function testVaultWithdrawalUsdt() public {
89+
uint256 usdtDepositAmount = 1_000e8;
90+
91+
_vaultDeposit(usdt, address(this), usdtDepositAmount);
92+
vault.withdraw(usdt, usdtDepositAmount);
93+
94+
assertEq(
95+
vault.balanceOf(address(this)),
96+
0,
97+
"vault usdt balance not 0"
98+
);
99+
assertEq(
100+
vault.totalSupplied(), 0, "vault total supplied not 0"
101+
);
102+
assertEq(
103+
IERC20(usdt).balanceOf(address(this)),
104+
usdtDepositAmount,
105+
"user's usdt balance not increased"
106+
);
107+
}
108+
109+
function testSwapTwoUsers() public {
110+
uint256 usdcDepositAmount = 1_000e6;
111+
uint256 usdtDepositAmount = 1_000e8;
112+
113+
_vaultDeposit(usdc, userA, usdcDepositAmount);
114+
_vaultDeposit(usdt, userB, usdtDepositAmount);
115+
116+
vm.prank(userA);
117+
vault.withdraw(usdt, usdcDepositAmount);
118+
assertEq(
119+
IERC20(usdt).balanceOf(userA),
120+
usdcDepositAmount,
121+
"userA usdt balance not increased"
122+
);
123+
124+
vm.prank(userB);
125+
vault.withdraw(usdc, usdcDepositAmount);
126+
assertEq(
127+
IERC20(usdc).balanceOf(userB),
128+
usdcDepositAmount,
129+
"userB usdc balance not increased"
130+
);
131+
assertEq(
132+
IERC20(usdt).balanceOf(userA),
133+
usdcDepositAmount,
134+
"userB usdt balance remains unchanged"
135+
);
136+
}
137+
138+
function _vaultDeposit(
139+
address token,
140+
address sender,
141+
uint256 amount
142+
) private {
143+
uint256 startingTotalSupplied = vault.totalSupplied();
144+
uint256 startingTotalBalance =
145+
IERC20(token).balanceOf(address(vault));
146+
uint256 startingUserBalance = vault.balanceOf(sender);
147+
148+
deal(token, sender, amount);
149+
150+
vm.startPrank(sender);
151+
IERC20(token).safeIncreaseAllowance(
152+
addresses.getAddress("V1_VAULT"), amount
153+
);
154+
155+
/// this executes 3 state transitions:
156+
/// 1. deposit dai into the vault
157+
/// 2. increase the user's balance in the vault
158+
/// 3. increase the total supplied amount in the vault
159+
vault.deposit(token, amount);
160+
vm.stopPrank();
161+
162+
uint256 normalizedAmount =
163+
vault.getNormalizedAmount(token, amount);
164+
165+
assertEq(
166+
vault.balanceOf(sender),
167+
startingUserBalance + normalizedAmount,
168+
"user vault balance not increased"
169+
);
170+
assertEq(
171+
vault.totalSupplied(),
172+
startingTotalSupplied + normalizedAmount,
173+
"vault total supplied not increased by deposited amount"
174+
);
175+
assertEq(
176+
IERC20(token).balanceOf(address(vault)),
177+
startingTotalBalance + amount,
178+
"token balance not increased"
179+
);
180+
}
181+
}
182+
183+
interface USDT {
184+
function approve(address, uint256) external;
185+
function transferFrom(address, address, uint256) external;
186+
}

test/TestVault02.t.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ pragma solidity ^0.8.0;
22

33
import {SafeERC20} from
44
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
5-
import {console} from "@forge-std/console.sol";
65
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
76
import {Test} from "@forge-std/Test.sol";
87

@@ -79,10 +78,6 @@ contract TestVault02 is Test, SIP02 {
7978
addresses.getAddress("V2_VAULT"), usdtDepositAmount
8079
);
8180

82-
/// this executes 3 state transitions:
83-
/// 1. deposit dai into the vault
84-
/// 2. increase the user's balance in the vault
85-
/// 3. increase the total supplied amount in the vault
8681
vault.deposit(usdt, usdtDepositAmount);
8782

8883
assertEq(
@@ -141,6 +136,11 @@ contract TestVault02 is Test, SIP02 {
141136

142137
vm.prank(userB);
143138
vault.withdraw(usdc, usdcDepositAmount);
139+
assertEq(
140+
IERC20(usdc).balanceOf(userB),
141+
usdcDepositAmount,
142+
"userB usdc balance not increased"
143+
);
144144
assertEq(
145145
IERC20(usdt).balanceOf(userA),
146146
usdcDepositAmount,

0 commit comments

Comments
 (0)