Skip to content

Commit 2f1bc83

Browse files
committed
tests
1 parent dbaed85 commit 2f1bc83

5 files changed

Lines changed: 212 additions & 17 deletions

File tree

src/NostalgicController.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ contract NostalgicController is AccessControl, INostalgicController {
4040
ZeroAddress()
4141
);
4242
factory = _factory;
43-
grantRole(DEFAULT_ADMIN_ROLE, initialAdmin);
43+
_grantRole(DEFAULT_ADMIN_ROLE, initialAdmin);
4444
}
4545

4646
modifier onlyOwnerOrFactory() {
@@ -60,7 +60,7 @@ contract NostalgicController is AccessControl, INostalgicController {
6060
(uint256 totalUsdCollateral, uint256 totalUsdBorrow) = userPosition(
6161
user
6262
);
63-
return totalUsdCollateral > totalUsdBorrow;
63+
return totalUsdCollateral >= totalUsdBorrow;
6464
}
6565

6666
function userPosition(

src/NostalgicJumpRateModel.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,4 @@ contract NostalgicJumpRateModel is INostalgicRateModel {
5050
SCALE_FACTOR;
5151
}
5252
}
53-
}
53+
}

src/NostalgicPool.sol

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
1515
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
1616
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
1717
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
18-
1918
// /$$ /$$ /$$ /$$ /$$ /$$$$$$$ /$$
2019
// | $$$ | $$ | $$ | $$ |__/ | $$__ $$ | $$
2120
// | $$$$| $$ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ | $$ /$$$$$$ /$$ /$$$$$$$| $$ \ $$ /$$$$$$ /$$$$$$ | $$
@@ -62,10 +61,6 @@ contract NostalgicPool is
6261

6362
uint256 internal lastUpdateBlockNumber;
6463

65-
constructor() {
66-
_disableInitializers();
67-
}
68-
6964
function initialize(
7065
IERC20 _underyingAsset,
7166
string memory _name,
@@ -128,33 +123,31 @@ contract NostalgicPool is
128123
emit RateModelUpdate(address(_rateModel));
129124
}
130125

131-
/**
132-
* Returns latest price scaled to token decimals
133-
* Example: if token has 6 decimals, price will be returned with 6 decimals
134-
*/
126+
// $ 1$ = 1e18
135127
function getUnderlyingPriceInUSD() public view returns (uint256) {
136128
(, int256 price, , , ) = priceFeed.latestRoundData();
137129
require(price > 0, InvalidPrice());
138130

139131
uint8 priceDecimals = priceFeed.decimals();
140132
uint8 tokenDecimals = IERC20Metadata(asset()).decimals();
141-
142133
// Scale price to token decimals
143134
if (priceDecimals < tokenDecimals) {
144-
return SafeCast.toUint256(price) * (10 ** (tokenDecimals - priceDecimals));
135+
return
136+
SafeCast.toUint256(price) *
137+
(10 ** (tokenDecimals - priceDecimals));
145138
} else {
146-
return SafeCast.toUint256(price) / (10 ** (priceDecimals - tokenDecimals));
139+
return
140+
SafeCast.toUint256(price) /
141+
(10 ** (priceDecimals - tokenDecimals));
147142
}
148143
}
149144

150-
151145
/**
152146
* Returns USD value of a given token amount (18-decimals result)
153147
*/
154148
function getTokenValueInUSD(uint256 amount) public view returns (uint256) {
155149
uint256 price = getUnderlyingPriceInUSD(); // price already aligned to token decimals
156150
uint8 tokenDecimals = IERC20Metadata(asset()).decimals();
157-
158151
// Normalize: (amount * price) / 10^tokenDecimals
159152
return (amount * price) / (10 ** tokenDecimals);
160153
}
@@ -382,6 +375,12 @@ contract NostalgicPool is
382375
emit FeesClaim(amount);
383376
}
384377

378+
function maxWithdraw(
379+
address
380+
) public pure override(ERC4626Upgradeable, IERC4626) returns (uint256) {
381+
return type(uint256).max;
382+
}
383+
385384
function _convertToAssets(
386385
uint256,
387386
Math.Rounding

test/NostalgicPool.t.sol

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
import {Test, console} from "forge-std/Test.sol";
5+
import {NostalgicPool} from "../src/NostalgicPool.sol";
6+
import {IAggregatorV3} from "../src/interfaces/IAggregatorV3.sol";
7+
import {MockERC20} from "./mocks/MockERC20.t.sol";
8+
import {MockPriceFeed} from "./mocks/MockPriceFeed.t.sol";
9+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
10+
import {NostalgicController} from "../src/NostalgicController.sol";
11+
import {NostalgicJumpRateModel} from "../src/NostalgicJumpRateModel.sol";
12+
import {INostalgicRateModel} from "../src/interfaces/INostalgicRateModel.sol";
13+
import {INostalgicPoolErrors} from "../src/interfaces/INostalgicPool.sol";
14+
contract NostalgicPoolTest is Test {
15+
NostalgicPool poolUsdc;
16+
NostalgicPool poolEth;
17+
18+
IERC20 usdc;
19+
IERC20 eth;
20+
21+
IAggregatorV3 priceFeedUsdc;
22+
IAggregatorV3 priceFeedEth;
23+
24+
NostalgicController controller;
25+
26+
INostalgicRateModel rateModel;
27+
28+
address alice = makeAddr("alice");
29+
address bob = makeAddr("bob");
30+
31+
function setUp() public {
32+
rateModel = new NostalgicJumpRateModel(0.1e18, 0.2e18, 1e18, 1e18); // @todo fix this later
33+
controller = new NostalgicController(
34+
address(this),
35+
makeAddr("factory")
36+
);
37+
priceFeedUsdc = new MockPriceFeed();
38+
MockPriceFeed(address(priceFeedUsdc)).setMockAnswer(100000000);
39+
priceFeedEth = new MockPriceFeed();
40+
MockPriceFeed(address(priceFeedEth)).setMockAnswer(438387325100);
41+
usdc = new MockERC20();
42+
eth = new MockERC20();
43+
poolUsdc = new NostalgicPool();
44+
poolEth = new NostalgicPool();
45+
46+
poolUsdc.initialize(
47+
usdc,
48+
"nstlUSDC",
49+
"nstlUSDC",
50+
controller,
51+
priceFeedUsdc,
52+
rateModel,
53+
address(this),
54+
address(this),
55+
0.001e18
56+
);
57+
poolEth.initialize(
58+
usdc,
59+
"nstlETH",
60+
"nstlUSDC",
61+
controller,
62+
priceFeedEth,
63+
rateModel,
64+
address(this),
65+
address(this),
66+
0.001e18
67+
);
68+
deal(address(usdc), alice, 10_000e18);
69+
deal(address(usdc), bob, 10_000e18);
70+
deal(address(eth), alice, 10e18);
71+
deal(address(eth), bob, 10e18);
72+
vm.startPrank(alice);
73+
usdc.approve(address(poolUsdc), type(uint256).max);
74+
eth.approve(address(poolEth), type(uint256).max);
75+
vm.stopPrank();
76+
77+
vm.prank(bob);
78+
usdc.approve(address(poolUsdc), type(uint256).max);
79+
eth.approve(address(poolEth), type(uint256).max);
80+
vm.stopPrank();
81+
}
82+
83+
function _depositUsdc(address user, uint256 depositAmount) internal {
84+
vm.startPrank(user);
85+
uint256 shares = poolUsdc.deposit(depositAmount, user);
86+
87+
assertEq(shares, depositAmount);
88+
assertEq(poolUsdc.balanceOf(user), depositAmount);
89+
vm.stopPrank();
90+
}
91+
92+
function testNotSupportedFunctions() public {
93+
vm.expectRevert(INostalgicPoolErrors.NotSupported.selector);
94+
poolUsdc.mint(1, address(1));
95+
vm.expectRevert(INostalgicPoolErrors.NotSupported.selector);
96+
poolUsdc.convertToAssets(1);
97+
vm.expectRevert(INostalgicPoolErrors.NotSupported.selector);
98+
poolUsdc.redeem(1, address(1), address(1));
99+
}
100+
function testDeposit() public {
101+
_depositUsdc(alice, 100e18);
102+
}
103+
104+
function testWithdraw() public {
105+
uint256 amount = 100e18;
106+
_depositUsdc(alice, amount);
107+
108+
vm.startPrank(alice);
109+
uint256 shares = poolUsdc.withdraw(amount, alice, alice);
110+
111+
assertEq(shares, amount);
112+
assertEq(poolUsdc.balanceOf(alice), 0);
113+
vm.stopPrank();
114+
}
115+
116+
function testDonate() public {
117+
uint256 amount = 100e18;
118+
vm.startPrank(alice);
119+
poolUsdc.donate(amount);
120+
vm.stopPrank();
121+
assertEq(poolUsdc.totalProtocolFees(), amount);
122+
}
123+
function testClaimFees() public {
124+
uint256 amount = 100e18;
125+
vm.startPrank(alice);
126+
poolUsdc.donate(amount);
127+
vm.stopPrank();
128+
assertEq(poolUsdc.totalProtocolFees(), amount);
129+
poolUsdc.claimFees(amount);
130+
assertEq(poolUsdc.totalProtocolFees(), 0);
131+
assertEq(usdc.balanceOf(address(this)), amount);
132+
}
133+
134+
function testGetTokenValueInUSD() public {
135+
console.log(poolUsdc.getTokenValueInUSD(1e18), 1e18);
136+
console.log(poolUsdc.getTokenValueInUSD(10e18), 10e18);
137+
console.log(
138+
poolEth.getTokenValueInUSD(1e18),
139+
438387325100000000000000000000
140+
);
141+
}
142+
}

test/mocks/MockPriceFeed.t.sol

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
import {IAggregatorV3} from "../../src/interfaces/IAggregatorV3.sol";
5+
6+
contract MockPriceFeed is IAggregatorV3 {
7+
int256 mockAnswer;
8+
9+
function decimals() external view returns (uint8) {
10+
return 8;
11+
}
12+
13+
function description() external view returns (string memory) {
14+
return "mock";
15+
}
16+
17+
function version() external view returns (uint256) {
18+
return 1;
19+
}
20+
21+
function getRoundData(
22+
uint80 _roundId
23+
)
24+
external
25+
view
26+
returns (
27+
uint80 roundId,
28+
int256 answer,
29+
uint256 startedAt,
30+
uint256 updatedAt,
31+
uint80 answeredInRound
32+
)
33+
{
34+
return (1, mockAnswer, 0, 0, 0);
35+
}
36+
37+
function latestRoundData()
38+
external
39+
view
40+
returns (
41+
uint80 roundId,
42+
int256 answer,
43+
uint256 startedAt,
44+
uint256 updatedAt,
45+
uint80 answeredInRound
46+
)
47+
{
48+
return (1, mockAnswer, 0, 0, 0);
49+
}
50+
51+
function setMockAnswer(int256 _mockAnswer) public {
52+
mockAnswer = _mockAnswer;
53+
}
54+
}

0 commit comments

Comments
 (0)