Files
uupl-smart-contract/test/BankV2.t.sol
T
2026-08-21 14:58:24 -06:00

166 lines
5.6 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity 0.8.35;
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {Options, Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
import {BankV1} from "../src/BankV1.sol";
import {BankV2} from "../src/BankV2.sol";
import {BankTestBase} from "./helpers/BankTestBase.sol";
event BalanceTransferred(address indexed from, address indexed to, uint256 amount);
contract BankV2Test is BankTestBase {
uint256 private constant ALICE_DEPOSIT = 1_000e6;
uint256 private constant BOB_DEPOSIT = 500e6;
BankV2 internal bankV2;
function setUp() public override {
super.setUp();
_deposit(alice, ALICE_DEPOSIT);
_deposit(bob, BOB_DEPOSIT);
Options memory opts;
opts.referenceContract = "BankV1.sol:BankV1";
Upgrades.upgradeProxy(proxy, "BankV2.sol:BankV2", "", opts, owner);
bankV2 = BankV2(proxy);
}
function testTransferBalanceMoves250MillionUnitsAndEmitsExactEvent() public {
vm.expectEmit(true, true, false, true, proxy);
emit BalanceTransferred(alice, bob, 250e6);
vm.prank(alice);
bankV2.transferBalance(bob, 250e6);
assertEq(bankV2.balanceOf(alice), 750e6);
assertEq(bankV2.balanceOf(bob), 750e6);
}
function testTransferBalanceLeavesLiabilitiesAndTokenReservesUnchanged() public {
uint256 liabilitiesBefore = bankV2.totalLiabilities();
uint256 reservesBefore = token.balanceOf(proxy);
vm.prank(alice);
bankV2.transferBalance(bob, 250e6);
assertEq(bankV2.totalLiabilities(), liabilitiesBefore);
assertEq(token.balanceOf(proxy), reservesBefore);
}
function testTransferBalanceRejectsZeroAmount() public {
vm.prank(alice);
vm.expectRevert(BankV1.ZeroAmount.selector);
bankV2.transferBalance(bob, 0);
}
function testTransferBalanceRejectsZeroRecipient() public {
vm.prank(alice);
vm.expectRevert(abi.encodeWithSelector(BankV2.InvalidRecipient.selector, address(0)));
bankV2.transferBalance(address(0), 1);
}
function testTransferBalanceRejectsSenderAsRecipient() public {
vm.prank(alice);
vm.expectRevert(BankV2.SelfTransfer.selector);
bankV2.transferBalance(alice, 1);
}
function testTransferBalanceReportsAvailableAndRequestedWhenBalanceIsInsufficient() public {
vm.prank(alice);
vm.expectRevert(
abi.encodeWithSelector(BankV1.InsufficientBalance.selector, alice, ALICE_DEPOSIT, ALICE_DEPOSIT + 1)
);
bankV2.transferBalance(bob, ALICE_DEPOSIT + 1);
assertEq(bankV2.balanceOf(alice), ALICE_DEPOSIT);
assertEq(bankV2.balanceOf(bob), BOB_DEPOSIT);
}
function testTransferBalanceRejectsCallsWhilePaused() public {
vm.prank(owner);
bankV2.pause();
vm.prank(alice);
vm.expectRevert(PausableUpgradeable.EnforcedPause.selector);
bankV2.transferBalance(bob, 1);
assertEq(bankV2.balanceOf(alice), ALICE_DEPOSIT);
assertEq(bankV2.balanceOf(bob), BOB_DEPOSIT);
}
function testTransferBalanceCreditsRecipientWithNoPreviousBalance() public {
assertEq(bankV2.balanceOf(stranger), 0);
vm.prank(alice);
bankV2.transferBalance(stranger, 125e6);
assertEq(bankV2.balanceOf(alice), 875e6);
assertEq(bankV2.balanceOf(stranger), 125e6);
}
function testFuzzTransferBalanceAcrossTrackedRecipientsAndSenderBoundedAmounts(
uint256 recipientSeed,
uint256 amountSeed
) public {
address recipient = _trackedRecipient(bound(recipientSeed, 0, 2));
uint256 amount = bound(amountSeed, 1, ALICE_DEPOSIT);
uint256 recipientBefore = bankV2.balanceOf(recipient);
uint256 liabilitiesBefore = bankV2.totalLiabilities();
uint256 reservesBefore = token.balanceOf(proxy);
vm.prank(alice);
bankV2.transferBalance(recipient, amount);
assertEq(bankV2.balanceOf(alice), ALICE_DEPOSIT - amount);
assertEq(bankV2.balanceOf(recipient), recipientBefore + amount);
assertEq(bankV2.totalLiabilities(), liabilitiesBefore);
assertEq(token.balanceOf(proxy), reservesBefore);
}
function testV1DepositWithdrawalViewsPauseAndUnpauseStillWorkThroughV2Proxy() public {
_mintAndApprove(stranger, 100e6);
vm.prank(stranger);
bankV2.deposit(100e6);
vm.prank(alice);
bankV2.withdraw(100e6);
assertEq(address(bankV2.asset()), address(token));
assertEq(bankV2.owner(), owner);
assertEq(bankV2.balanceOf(alice), 900e6);
assertEq(bankV2.balanceOf(bob), BOB_DEPOSIT);
assertEq(bankV2.balanceOf(stranger), 100e6);
assertEq(bankV2.totalLiabilities(), 1_500e6);
assertEq(token.balanceOf(proxy), 1_500e6);
assertEq(bankV2.contractVersion(), 2);
vm.prank(owner);
bankV2.pause();
assertTrue(bankV2.paused());
vm.prank(owner);
bankV2.unpause();
assertFalse(bankV2.paused());
}
function _deposit(address account, uint256 amount) private {
_mintAndApprove(account, amount);
vm.prank(account);
bank.deposit(amount);
}
function _mintAndApprove(address account, uint256 amount) private {
vm.prank(owner);
token.mint(account, amount);
vm.prank(account);
token.approve(proxy, amount);
}
function _trackedRecipient(uint256 index) private view returns (address) {
if (index == 0) return bob;
if (index == 1) return stranger;
return owner;
}
}