298 lines
10 KiB
Solidity
298 lines
10 KiB
Solidity
pragma solidity 0.8.20;
|
|
|
|
import {Test} from "forge-std/Test.sol";
|
|
import {Reserve} from "../../src/mocks/Reserve.sol";
|
|
|
|
contract ReserveTest is Test {
|
|
address constant INITIALIZER = 0x0000000000000000000000000000000000000001;
|
|
address constant FAUCET_ADDRESS = 0x0000000000000000000000000000000000000002;
|
|
address constant ALICE_ADDRESS = 0x0000000000000000000000000000000000000003;
|
|
address constant BOB_ADDRESS = 0x0000000000000000000000000000000000000004;
|
|
uint256 constant CONVERSION_RATE = 69 * 10e5;
|
|
uint256 constant SEND_AMOUNT = 1e16;
|
|
|
|
string constant NAME = "Test DAI";
|
|
string constant SYMBOL = "tDAI";
|
|
|
|
Reserve reserve;
|
|
|
|
event Transfer(address indexed from, address indexed to, uint256 value);
|
|
event LogStakingContractUpdated(address stakingContract);
|
|
|
|
function setUp() public {
|
|
vm.prank(INITIALIZER);
|
|
reserve = new Reserve(
|
|
"Test DAI",
|
|
"tDAI",
|
|
CONVERSION_RATE
|
|
);
|
|
}
|
|
|
|
function test_isConstructedCorrectly() public view {
|
|
assertEq(reserve.name(), NAME);
|
|
assertEq(reserve.symbol(), SYMBOL);
|
|
assertEq(reserve.decimals(), 18);
|
|
assertEq(reserve.totalSupply(), 0);
|
|
|
|
assertEq(reserve.donationRate(), 0);
|
|
assertEq(reserve.conversionRate(), CONVERSION_RATE);
|
|
}
|
|
|
|
function test_mint_couldBeDoneWithValue() public {
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS);
|
|
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), SEND_AMOUNT * CONVERSION_RATE);
|
|
}
|
|
|
|
function test_mint_couldNotBeDoneWithoutEmptyValue() public {
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint(ALICE_ADDRESS);
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
}
|
|
|
|
function test_mint_couldNotMintIfNotEnoughValue() public {
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
bool didRevert = false;
|
|
|
|
vm.prank(ALICE_ADDRESS);
|
|
try reserve.mint{ value: type(uint256).max }(ALICE_ADDRESS) {
|
|
} catch {
|
|
didRevert = true;
|
|
}
|
|
|
|
assertEq(didRevert, true);
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
}
|
|
|
|
function test_mint_superMintCouldBeDoneFromDeployer() public {
|
|
assertEq(reserve.balanceOf(INITIALIZER), 0);
|
|
vm.prank(INITIALIZER);
|
|
reserve.superMint(INITIALIZER, 420 * 1e18);
|
|
assertEq(reserve.balanceOf(INITIALIZER), 420 * 1e18);
|
|
}
|
|
|
|
function test_mint_superMintCouldNotBeDoneFromArbitraryAddress() public {
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
vm.expectRevert();
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.superMint(ALICE_ADDRESS, 420 * 1e18);
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
}
|
|
|
|
function test_mint_donationNotTakenIfRateNotSet() public {
|
|
assertEq(reserve.totalSupply(), 0);
|
|
assertEq(reserve.donationRate(), 0);
|
|
assertEq(reserve.accumulatedDonation(), 0);
|
|
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS);
|
|
|
|
assertEq(reserve.totalSupply(), SEND_AMOUNT * CONVERSION_RATE);
|
|
assertEq(reserve.donationRate(), 0);
|
|
assertEq(reserve.accumulatedDonation(), 0);
|
|
}
|
|
|
|
function test_mint_donationIsTakenIfRateExists() public {
|
|
assertEq(reserve.totalSupply(), 0);
|
|
assertEq(reserve.donationRate(), 0);
|
|
assertEq(reserve.accumulatedDonation(), 0);
|
|
|
|
vm.prank(INITIALIZER);
|
|
reserve.changeDonationRate(1e4); // 10%
|
|
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS);
|
|
|
|
assertEq(reserve.totalSupply(), SEND_AMOUNT * CONVERSION_RATE);
|
|
assertEq(reserve.donationRate(), 1e4);
|
|
assertEq(reserve.accumulatedDonation(), SEND_AMOUNT * 1e4 / 1e5);
|
|
}
|
|
|
|
function test_rate_couldBeChangedByDeployer() public {
|
|
assertEq(reserve.conversionRate(), CONVERSION_RATE);
|
|
vm.prank(INITIALIZER);
|
|
reserve.changeRate(1337);
|
|
assertEq(reserve.conversionRate(), 1337);
|
|
}
|
|
|
|
function test_rate_couldNotBeChangedByArbitraryAddress() public {
|
|
assertEq(reserve.conversionRate(), CONVERSION_RATE);
|
|
vm.expectRevert();
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.changeRate(1337);
|
|
assertEq(reserve.conversionRate(), CONVERSION_RATE);
|
|
}
|
|
|
|
function test_withdraw_couldBeDoneByDeployer() public {
|
|
assertEq(address(reserve).balance, 0);
|
|
vm.prank(INITIALIZER);
|
|
reserve.changeDonationRate(1e5);
|
|
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS);
|
|
|
|
assertEq(address(reserve).balance, SEND_AMOUNT);
|
|
|
|
vm.prank(INITIALIZER);
|
|
reserve.withdraw(payable(FAUCET_ADDRESS));
|
|
|
|
assertEq(address(reserve).balance, 0);
|
|
assertEq(FAUCET_ADDRESS.balance, SEND_AMOUNT);
|
|
}
|
|
|
|
function test_withdraw_onlyAccumulatedDonationsCouldBeWithdrawn() public {
|
|
assertEq(address(reserve).balance, 0);
|
|
vm.prank(INITIALIZER);
|
|
reserve.changeDonationRate(5 * 1e4); // 50%
|
|
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS);
|
|
|
|
assertEq(address(reserve).balance, SEND_AMOUNT);
|
|
|
|
vm.prank(INITIALIZER);
|
|
reserve.withdraw(payable(FAUCET_ADDRESS));
|
|
assertEq(address(reserve).balance, SEND_AMOUNT / 2);
|
|
assertEq(FAUCET_ADDRESS.balance, SEND_AMOUNT / 2);
|
|
|
|
vm.prank(INITIALIZER);
|
|
reserve.withdraw(payable(FAUCET_ADDRESS));
|
|
assertEq(address(reserve).balance, SEND_AMOUNT / 2);
|
|
assertEq(FAUCET_ADDRESS.balance, SEND_AMOUNT / 2);
|
|
}
|
|
|
|
function test_withdraw_couldNotBeDoneByArbitraryAddress() public {
|
|
assertEq(address(reserve).balance, 0);
|
|
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS);
|
|
|
|
assertEq(address(reserve).balance, SEND_AMOUNT);
|
|
|
|
vm.expectRevert();
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.withdraw(payable(ALICE_ADDRESS));
|
|
|
|
assertEq(address(reserve).balance, SEND_AMOUNT);
|
|
assertEq(ALICE_ADDRESS.balance, 0);
|
|
}
|
|
|
|
function test_burn_shouldReturnFullAmountIfRateNotSet() public {
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS);
|
|
|
|
uint256 balance = reserve.balanceOf(ALICE_ADDRESS);
|
|
assertEq(reserve.totalSupply(), SEND_AMOUNT * CONVERSION_RATE);
|
|
assertEq(reserve.totalSupply(), balance);
|
|
assertEq(reserve.accumulatedDonation(), 0);
|
|
assertEq(ALICE_ADDRESS.balance, 0);
|
|
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.burn(balance);
|
|
|
|
assertEq(reserve.totalSupply(), 0);
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
assertEq(reserve.accumulatedDonation(), 0);
|
|
assertEq(ALICE_ADDRESS.balance, SEND_AMOUNT);
|
|
}
|
|
|
|
function test_burn_shouldTakeDonationInAccordanceToRate() public {
|
|
vm.prank(INITIALIZER);
|
|
reserve.changeDonationRate(5 * 1e4); // 50%
|
|
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS);
|
|
|
|
uint256 balance = reserve.balanceOf(ALICE_ADDRESS);
|
|
assertEq(reserve.totalSupply(), SEND_AMOUNT * CONVERSION_RATE);
|
|
assertEq(reserve.totalSupply(), balance);
|
|
assertEq(reserve.accumulatedDonation(), SEND_AMOUNT / 2);
|
|
assertEq(ALICE_ADDRESS.balance, 0);
|
|
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.burn(balance);
|
|
|
|
assertEq(reserve.totalSupply(), 0);
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
assertEq(reserve.accumulatedDonation(), SEND_AMOUNT / 2);
|
|
assertEq(ALICE_ADDRESS.balance, SEND_AMOUNT / 2);
|
|
}
|
|
|
|
function test_burn_multipleUsersAccumulateInTotal() public {
|
|
vm.prank(INITIALIZER);
|
|
reserve.changeDonationRate(5 * 1e4); // 50%
|
|
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(ALICE_ADDRESS);
|
|
|
|
vm.prank(INITIALIZER);
|
|
reserve.changeRate(CONVERSION_RATE * 9);
|
|
|
|
deal(BOB_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(BOB_ADDRESS);
|
|
reserve.mint{ value: SEND_AMOUNT }(BOB_ADDRESS);
|
|
|
|
assertEq(ALICE_ADDRESS.balance, 0);
|
|
assertEq(BOB_ADDRESS.balance, 0);
|
|
uint256 aliceBalance = reserve.balanceOf(ALICE_ADDRESS);
|
|
uint256 bobBalance = reserve.balanceOf(BOB_ADDRESS);
|
|
|
|
uint256 bobEstimation = reserve.estimateAmount(bobBalance);
|
|
uint256 aliceEstimation = reserve.estimateAmount(aliceBalance);
|
|
|
|
vm.prank(BOB_ADDRESS);
|
|
reserve.burn(bobBalance);
|
|
|
|
vm.prank(ALICE_ADDRESS);
|
|
reserve.burn(aliceBalance);
|
|
|
|
assertEq(BOB_ADDRESS.balance, SEND_AMOUNT * 9 / 10);
|
|
assertEq(BOB_ADDRESS.balance, bobEstimation);
|
|
assertEq(ALICE_ADDRESS.balance, SEND_AMOUNT / 10);
|
|
assertEq(ALICE_ADDRESS.balance, aliceEstimation);
|
|
|
|
assertEq(reserve.totalSupply(), 0);
|
|
assertEq(reserve.accumulatedDonation(), SEND_AMOUNT);
|
|
assertEq(address(reserve).balance, SEND_AMOUNT);
|
|
}
|
|
|
|
function test_reserveFallback() public {
|
|
assertEq(address(reserve).balance, 0);
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
|
|
vm.prank(ALICE_ADDRESS);
|
|
(bool success, ) = address(reserve).call(abi.encodeWithSignature("nonExistentFunction()"));
|
|
require(success, "Fallback call failed");
|
|
|
|
assertEq(address(reserve).balance, 0);
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
}
|
|
|
|
function test_reserveReceive() public {
|
|
assertEq(address(reserve).balance, 0);
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), 0);
|
|
|
|
deal(ALICE_ADDRESS, SEND_AMOUNT);
|
|
vm.prank(ALICE_ADDRESS);
|
|
(bool success, ) = address(reserve).call{value: SEND_AMOUNT}("");
|
|
require(success, "Transfer of native failed");
|
|
|
|
uint256 estimatedReceiveAmount = SEND_AMOUNT * reserve.conversionRate();
|
|
assertEq(address(reserve).balance, SEND_AMOUNT);
|
|
assertEq(reserve.balanceOf(ALICE_ADDRESS), estimatedReceiveAmount);
|
|
}
|
|
}
|