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 }