/ test / CommunityVault.t.sol
CommunityVault.t.sol
  1  // SPDX-License-Identifier: UNLICENSED
  2  
  3  pragma solidity ^0.8.17;
  4  
  5  import { Test } from "forge-std/Test.sol";
  6  import { TestERC20Token } from "../contracts/mocks/TestERC20Token.sol";
  7  import { TestERC721Token } from "../contracts/mocks/TestERC721Token.sol";
  8  import { CommunityVault } from "../contracts/CommunityVault.sol";
  9  import { CommunityOwnable } from "../contracts/CommunityOwnable.sol";
 10  import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
 11  import { DeployOwnerAndMasterToken } from "../script/DeployOwnerAndMasterToken.s.sol";
 12  import { CommunityERC20 } from "../contracts/tokens/CommunityERC20.sol";
 13  import { OwnerToken } from "../contracts/tokens/OwnerToken.sol";
 14  import { MasterToken } from "../contracts/tokens/MasterToken.sol";
 15  
 16  contract CommunityVaultTest is Test {
 17      CommunityVault internal vault;
 18  
 19      address[] internal accounts = new address[](2);
 20      address internal deployer;
 21  
 22      TestERC20Token internal erc20Token;
 23      TestERC721Token internal erc721Token;
 24      CommunityERC20 internal communityERC20Token;
 25      OwnerToken internal ownerToken;
 26      MasterToken internal masterToken;
 27  
 28      function setUp() public virtual {
 29          DeploymentConfig deploymentConfig;
 30          DeployOwnerAndMasterToken deployment = new DeployOwnerAndMasterToken();
 31          (ownerToken, masterToken, deploymentConfig) = deployment.run();
 32  
 33          deployer = deploymentConfig.deployer();
 34  
 35          erc20Token = new TestERC20Token();
 36          erc721Token = new TestERC721Token();
 37  
 38          communityERC20Token = new CommunityERC20("Test", "TST", 18, 100, "", address(ownerToken), address(masterToken));
 39  
 40          vault = new CommunityVault(address(ownerToken), address(masterToken));
 41  
 42          accounts[0] = makeAddr("one");
 43          accounts[1] = makeAddr("two");
 44      }
 45  
 46      function test_Deployment() public {
 47          assertEq(vault.ownerToken(), address(ownerToken));
 48          assertEq(vault.masterToken(), address(masterToken));
 49      }
 50  }
 51  
 52  contract CommunityVaultBaseERC20Test is CommunityVaultTest {
 53      function setUp() public virtual override {
 54          CommunityVaultTest.setUp();
 55          erc20Token.mint(accounts[0], 10e18);
 56      }
 57  }
 58  
 59  contract TransferERC20ByNonAdminTest is CommunityVaultBaseERC20Test {
 60      function setUp() public virtual override {
 61          CommunityVaultBaseERC20Test.setUp();
 62      }
 63  
 64      function test_revertIfCalledByNonAdmin() public {
 65          uint256[] memory amounts = new uint256[](2);
 66          amounts[0] = 1;
 67          amounts[1] = 1;
 68  
 69          vm.prank(accounts[0]);
 70  
 71          vm.expectRevert(CommunityOwnable.CommunityOwnable_NotAuthorized.selector);
 72          vault.transferERC20(address(erc20Token), accounts, amounts);
 73      }
 74  }
 75  
 76  contract TransferERC20ByAdminTest is CommunityVaultBaseERC20Test {
 77      uint256 private depositAmount = 10e18;
 78  
 79      function setUp() public virtual override {
 80          CommunityVaultBaseERC20Test.setUp();
 81  
 82          vm.startPrank(accounts[0]);
 83          erc20Token.approve(address(vault), depositAmount);
 84          vault.depositERC20(address(erc20Token), depositAmount);
 85          vm.stopPrank();
 86      }
 87  
 88      function test_LengthMismatch() public {
 89          uint256[] memory amounts = new uint256[](1);
 90          amounts[0] = 5e18;
 91  
 92          vm.prank(deployer);
 93          vm.expectRevert(CommunityVault.CommunityVault_LengthMismatch.selector);
 94          vault.transferERC20(address(erc20Token), accounts, amounts);
 95      }
 96  
 97      function test_TransferAmountZero() public {
 98          uint256[] memory amounts = new uint256[](2);
 99          amounts[0] = 5e18;
100          amounts[1] = 0;
101  
102          vm.prank(deployer);
103          vm.expectRevert(CommunityVault.CommunityVault_TransferAmountZero.selector);
104          vault.transferERC20(address(erc20Token), accounts, amounts);
105      }
106  
107      function test_NoRecipients() public {
108          uint256[] memory amounts = new uint256[](0);
109          address[] memory tmpAccounts = new address[](0);
110  
111          vm.prank(deployer);
112          vm.expectRevert(CommunityVault.CommunityVault_NoRecipients.selector);
113          vault.transferERC20(address(erc20Token), tmpAccounts, amounts);
114      }
115  
116      function test_AdminCanTransferERC20() public {
117          assertEq(erc20Token.balanceOf(address(vault)), 10e18);
118          assertEq(vault.erc20TokenBalances(address(erc20Token)), 10e18);
119  
120          uint256[] memory amounts = new uint256[](2);
121          amounts[0] = 3e18;
122          amounts[1] = 3e18;
123  
124          vm.prank(deployer);
125          vault.transferERC20(address(erc20Token), accounts, amounts);
126  
127          assertEq(erc20Token.balanceOf(address(vault)), 4e18);
128          assertEq(vault.erc20TokenBalances(address(erc20Token)), 4e18);
129      }
130  
131      function test_TransferERC20AmountTooBig() public {
132          assertEq(erc20Token.balanceOf(address(vault)), 10e18);
133          assertEq(vault.erc20TokenBalances(address(erc20Token)), 10e18);
134  
135          uint256[] memory amounts = new uint256[](2);
136          amounts[0] = 10e18;
137          amounts[1] = 10e18;
138  
139          vm.prank(deployer);
140          vm.expectRevert(CommunityVault.CommunityVault_ERC20TransferAmountTooBig.selector);
141          vault.transferERC20(address(erc20Token), accounts, amounts);
142      }
143  }
144  
145  contract DepositERC20Test is CommunityVaultBaseERC20Test {
146      function testSuccessfulDepositERC20() public {
147          uint256 depositAmount = 5;
148          uint256 initialVaultBalance = erc20Token.balanceOf(address(vault));
149          uint256 initialTokenBalanceValue = vault.erc20TokenBalances(address(erc20Token));
150  
151          vm.startPrank(accounts[0]);
152          erc20Token.approve(address(vault), depositAmount);
153          vault.depositERC20(address(erc20Token), depositAmount);
154          vm.stopPrank();
155  
156          assertEq(erc20Token.balanceOf(address(vault)), initialVaultBalance + depositAmount);
157          assertEq(vault.erc20TokenBalances(address(erc20Token)), initialTokenBalanceValue + depositAmount);
158      }
159  
160      function testDepositZeroTokens() public {
161          vm.prank(accounts[0]);
162          vm.expectRevert(CommunityVault.CommunityVault_DepositAmountZero.selector);
163          vault.depositERC20(address(erc20Token), 0);
164      }
165  }
166  
167  contract CommunityVaultWithdrawUntrackedERC20Test is CommunityVaultBaseERC20Test {
168      function setUp() public virtual override {
169          CommunityVaultBaseERC20Test.setUp();
170          assertEq(erc20Token.balanceOf(accounts[0]), 10e18);
171  
172          vm.startPrank(accounts[0]);
173  
174          // deposit 2 tokens
175          erc20Token.approve(address(vault), 2e18);
176          vault.depositERC20(address(erc20Token), 2e18);
177  
178          // trasfer 8 tokens
179          erc20Token.transfer(address(vault), 8e18);
180          vm.stopPrank();
181      }
182  
183      function testRevertWithdrawalIfAmountIsMoreThanTheUntracked() public {
184          vm.prank(deployer);
185          vm.expectRevert(CommunityVault.CommunityVault_AmountExceedsUntrackedBalanceERC20.selector);
186          vault.withdrawUntrackedERC20(address(erc20Token), 9e18, accounts[0]);
187      }
188  
189      function testSuccessfulWithdrawal() public {
190          assertEq(erc20Token.balanceOf(accounts[0]), 0e18);
191          assertEq(erc20Token.balanceOf(address(vault)), 10e18);
192  
193          vm.prank(deployer);
194          vault.withdrawUntrackedERC20(address(erc20Token), 8e18, accounts[0]);
195  
196          assertEq(erc20Token.balanceOf(accounts[0]), 8e18);
197          assertEq(erc20Token.balanceOf(address(vault)), 2e18);
198      }
199  }
200  
201  contract CommunityVaultBaseERC721Test is CommunityVaultTest {
202      function setUp() public virtual override {
203          CommunityVaultTest.setUp();
204  
205          // mint 4 token to user
206          address user = accounts[0];
207          erc721Token.mint(user);
208          erc721Token.mint(user);
209          erc721Token.mint(user);
210          erc721Token.mint(user);
211      }
212  }
213  
214  contract CommunityVaultBaseTransferERC721Test is CommunityVaultBaseERC721Test {
215      function setUp() public virtual override {
216          CommunityVaultBaseERC721Test.setUp();
217  
218          address user = accounts[0];
219  
220          // user transfer 2 tokens to the vault
221          uint256[] memory ids = new uint256[](3);
222          ids[0] = 0;
223          ids[1] = 1;
224          ids[2] = 2;
225  
226          vm.startPrank(user);
227          erc721Token.approve(address(vault), ids[0]);
228          erc721Token.approve(address(vault), ids[1]);
229          erc721Token.approve(address(vault), ids[2]);
230          vault.depositERC721(address(erc721Token), ids);
231          vm.stopPrank();
232      }
233  }
234  
235  contract TransferERC721ByNonAdminTest is CommunityVaultBaseTransferERC721Test {
236      function setUp() public virtual override {
237          CommunityVaultBaseTransferERC721Test.setUp();
238      }
239  
240      function test_RevertIfCalledByNonAdmin() public {
241          uint256[] memory ids = new uint256[](2);
242          ids[0] = 0;
243          ids[1] = 1;
244  
245          vm.prank(accounts[0]);
246          vm.expectRevert(CommunityOwnable.CommunityOwnable_NotAuthorized.selector);
247  
248          vault.transferERC721(address(erc721Token), accounts, ids);
249      }
250  }
251  
252  contract TransferERC721ByAdminTest is CommunityVaultBaseTransferERC721Test {
253      function setUp() public virtual override {
254          CommunityVaultBaseTransferERC721Test.setUp();
255      }
256  
257      function test_LengthMismatch() public {
258          uint256[] memory ids = new uint256[](1);
259          ids[0] = 0;
260  
261          vm.prank(deployer);
262          vm.expectRevert(CommunityVault.CommunityVault_LengthMismatch.selector);
263          vault.transferERC721(address(erc721Token), accounts, ids);
264      }
265  
266      function test_NoRecipients() public {
267          uint256[] memory ids = new uint256[](0);
268          address[] memory tmpAccounts = new address[](0);
269  
270          vm.prank(deployer);
271          vm.expectRevert(CommunityVault.CommunityVault_NoRecipients.selector);
272          vault.transferERC721(address(erc721Token), tmpAccounts, ids);
273      }
274  
275      function test_AdminCanTransferERC721() public {
276          assertEq(erc721Token.balanceOf(address(vault)), 3);
277          assertEq(vault.erc721TokenBalances(address(erc721Token)), 3);
278  
279          // accounts[0] has 1 token with id 3
280          assertEq(erc721Token.balanceOf(accounts[0]), 1);
281          assertEq(erc721Token.balanceOf(accounts[1]), 0);
282  
283          assertEq(erc721Token.ownerOf(0), address(vault));
284          assertEq(erc721Token.ownerOf(1), address(vault));
285          assertEq(erc721Token.ownerOf(2), address(vault));
286  
287          uint256[] memory ids = new uint256[](2);
288          ids[0] = 0;
289          ids[1] = 1;
290  
291          vm.prank(deployer);
292          vault.transferERC721(address(erc721Token), accounts, ids);
293  
294          assertEq(erc721Token.balanceOf(address(vault)), 1);
295          assertEq(vault.erc721TokenBalances(address(erc721Token)), 1);
296  
297          assertEq(erc721Token.balanceOf(accounts[0]), 2);
298          assertEq(erc721Token.balanceOf(accounts[1]), 1);
299      }
300  
301      function test_RevertOnTransferERC721IfNotDeposited() public {
302          // id 3 is not deposited
303          assertEq(erc721Token.ownerOf(3), address(accounts[0]));
304  
305          uint256[] memory ids = new uint256[](1);
306          ids[0] = 3;
307  
308          address[] memory accountsList = new address[](1);
309          accountsList[0] = accounts[0];
310  
311          vm.prank(deployer);
312          vm.expectRevert(CommunityVault.CommunityVault_ERC721TokenNotDeposited.selector);
313          vault.transferERC721(address(erc721Token), accountsList, ids);
314      }
315  }
316  
317  contract CommunityVaultDepositERC721Test is CommunityVaultBaseERC721Test {
318      function setUp() public virtual override {
319          CommunityVaultBaseERC721Test.setUp();
320      }
321  
322      function testSuccessfulDepositERC721() public {
323          uint256[] memory ids = new uint256[](2);
324          ids[0] = 0;
325          ids[1] = 1;
326  
327          uint256 initialVaultBalance = erc721Token.balanceOf(address(vault));
328          uint256 initialTokenBalanceValue = vault.erc721TokenBalances(address(erc721Token));
329  
330          vm.startPrank(accounts[0]);
331          erc721Token.approve(address(vault), ids[0]);
332          erc721Token.approve(address(vault), ids[1]);
333          vault.depositERC721(address(erc721Token), ids);
334          vm.stopPrank();
335  
336          assertEq(erc721Token.balanceOf(address(vault)), initialVaultBalance + 2);
337          assertEq(vault.erc721TokenBalances(address(erc721Token)), initialTokenBalanceValue + 2);
338      }
339  }
340  
341  contract CommunityVaultWithdrawUntrackedERC721Test is CommunityVaultBaseERC721Test {
342      function setUp() public virtual override {
343          CommunityVaultBaseERC721Test.setUp();
344          vm.startPrank(accounts[0]);
345          // trasfer to contract ids 0 and 1
346          erc721Token.transferFrom(accounts[0], address(vault), 0);
347          erc721Token.transferFrom(accounts[0], address(vault), 1);
348  
349          // deposit id 2
350          uint256[] memory ids = new uint256[](1);
351          ids[0] = 2;
352          erc721Token.approve(address(vault), 2);
353          vault.depositERC721(address(erc721Token), ids);
354          vm.stopPrank();
355      }
356  
357      function testRevertWithdrawalIfTokenIsTracked() public {
358          uint256[] memory ids = new uint256[](1);
359          ids[0] = 2;
360  
361          assertEq(erc721Token.ownerOf(2), address(vault));
362          assertEq(vault.getERC721DepositedTokenByIndex(address(erc721Token), 0), 2);
363  
364          vm.prank(deployer);
365          vm.expectRevert(CommunityVault.CommunityVault_CannotWithdrawTrackedERC721.selector);
366          vault.withdrawUntrackedERC721(address(erc721Token), ids, accounts[0]);
367      }
368  
369      function testSuccessfulWithdrUntrackedERC721() public {
370          uint256[] memory ids = new uint256[](2);
371          ids[0] = 0;
372          ids[1] = 1;
373  
374          assertEq(erc721Token.ownerOf(0), address(vault));
375          assertEq(erc721Token.ownerOf(1), address(vault));
376  
377          vm.prank(deployer);
378          vault.withdrawUntrackedERC721(address(erc721Token), ids, accounts[0]);
379  
380          assertEq(erc721Token.ownerOf(0), accounts[0]);
381          assertEq(erc721Token.ownerOf(1), accounts[0]);
382      }
383  }
384  
385  contract CommunityVaultMigrationTest is CommunityVaultTest {
386      CommunityVault internal newVault;
387      TestERC20Token internal erc20Token2;
388      TestERC20Token internal erc20Token3;
389  
390      function setUp() public virtual override {
391          CommunityVaultTest.setUp();
392  
393          newVault = new CommunityVault(address(ownerToken), address(masterToken));
394          erc20Token2 = new TestERC20Token();
395          erc20Token3 = new TestERC20Token();
396  
397          vm.startPrank(deployer);
398          // mint erc20 tokens and deposit
399          erc20Token.mint(deployer, 10e18);
400          erc20Token.approve(address(vault), 10e18);
401          vault.depositERC20(address(erc20Token), 10e18);
402          erc20Token2.mint(deployer, 5e18);
403          erc20Token2.approve(address(vault), 5e18);
404          vault.depositERC20(address(erc20Token2), 5e18);
405  
406          // mint erc721 tokens and deposit
407          erc721Token.mint(deployer);
408          erc721Token.mint(deployer);
409          erc721Token.mint(deployer);
410          erc721Token.mint(deployer);
411          // id 4 is not deposited
412          erc721Token.mint(deployer);
413  
414          uint256[] memory ids = new uint256[](4);
415          ids[0] = 0;
416          ids[1] = 1;
417          ids[2] = 2;
418          ids[3] = 3;
419          erc721Token.approve(address(vault), 0);
420          erc721Token.approve(address(vault), 1);
421          erc721Token.approve(address(vault), 2);
422          erc721Token.approve(address(vault), 3);
423          vault.depositERC721(address(erc721Token), ids);
424  
425          vm.stopPrank();
426      }
427  
428      function test_migrateERC20RevertsIfNotAuthorized() public {
429          vm.prank(accounts[0]);
430          vm.expectRevert(CommunityOwnable.CommunityOwnable_NotAuthorized.selector);
431  
432          address[] memory tokens = new address[](0);
433          vault.migrateERC20Tokens(tokens);
434      }
435  
436      function test_migrateERC721RevertsIfNotAuthorized() public {
437          vm.prank(accounts[0]);
438          vm.expectRevert(CommunityOwnable.CommunityOwnable_NotAuthorized.selector);
439  
440          uint256[] memory ids = new uint256[](0);
441          vault.migrateERC721Tokens(address(0), ids);
442      }
443  
444      function test_migrateERC20RevertsIfNewImplementationIsNotSet() public {
445          assertEq(vault.newImplementation(), address(0));
446          vm.prank(deployer);
447          vm.expectRevert(CommunityVault.CommunityVault_NewImplementationNotSet.selector);
448  
449          address[] memory tokens = new address[](0);
450          vault.migrateERC20Tokens(tokens);
451      }
452  
453      function test_migrateERC721RevertsIfNewImplementationIsNotSet() public {
454          assertEq(vault.newImplementation(), address(0));
455          vm.prank(deployer);
456          vm.expectRevert(CommunityVault.CommunityVault_NewImplementationNotSet.selector);
457  
458          uint256[] memory ids = new uint256[](0);
459          vault.migrateERC721Tokens(address(0), ids);
460      }
461  
462      function test_migrateERC20RevertsIfTokenBalanceIsZero() public {
463          vm.startPrank(deployer);
464          vault.setNewImplementation(address(newVault));
465  
466          assertEq(erc20Token3.balanceOf(address(vault)), 0);
467          vm.expectRevert(CommunityVault.CommunityVault_ZeroBalance.selector);
468  
469          address[] memory tokens = new address[](1);
470          tokens[0] = address(erc20Token3);
471  
472          vault.migrateERC20Tokens(tokens);
473  
474          vm.stopPrank();
475      }
476  
477      function test_migrateERC20Tokens() public {
478          vm.startPrank(deployer);
479  
480          vault.setNewImplementation(address(newVault));
481          assertEq(erc20Token.balanceOf(address(vault)), 10e18);
482          assertEq(erc20Token2.balanceOf(address(vault)), 5e18);
483          assertEq(erc20Token.balanceOf(address(newVault)), 0);
484          assertEq(erc20Token2.balanceOf(address(newVault)), 0);
485  
486          address[] memory tokens = new address[](2);
487          tokens[0] = address(erc20Token);
488          tokens[1] = address(erc20Token2);
489          vault.migrateERC20Tokens(tokens);
490  
491          assertEq(erc20Token.balanceOf(address(vault)), 0);
492          assertEq(erc20Token2.balanceOf(address(vault)), 0);
493          assertEq(erc20Token.balanceOf(address(newVault)), 10e18);
494          assertEq(erc20Token2.balanceOf(address(newVault)), 5e18);
495  
496          vm.stopPrank();
497      }
498  
499      function test_migrateERC721TokensRevertsIfTokenNotDeposited() public {
500          vm.startPrank(deployer);
501  
502          vault.setNewImplementation(address(newVault));
503          assertEq(erc721Token.ownerOf(4), deployer);
504  
505          uint256[] memory ids = new uint256[](1);
506          ids[0] = 4;
507  
508          vm.expectRevert(CommunityVault.CommunityVault_ERC721TokenNotDeposited.selector);
509          vault.migrateERC721Tokens(address(erc721Token), ids);
510  
511          vm.stopPrank();
512      }
513  
514      function test_migrateERC721Tokens() public {
515          vm.startPrank(deployer);
516  
517          vault.setNewImplementation(address(newVault));
518          assertEq(erc721Token.ownerOf(0), address(vault));
519          assertEq(erc721Token.ownerOf(1), address(vault));
520          assertEq(erc721Token.ownerOf(2), address(vault));
521          assertEq(erc721Token.ownerOf(3), address(vault));
522  
523          uint256[] memory ids = new uint256[](4);
524          ids[0] = 0;
525          ids[1] = 1;
526          ids[2] = 2;
527          ids[3] = 3;
528  
529          vault.migrateERC721Tokens(address(erc721Token), ids);
530  
531          assertEq(erc721Token.ownerOf(0), address(newVault));
532          assertEq(erc721Token.ownerOf(1), address(newVault));
533          assertEq(erc721Token.ownerOf(2), address(newVault));
534          assertEq(erc721Token.ownerOf(3), address(newVault));
535  
536          vm.stopPrank();
537      }
538  }