Skip to content

Commit af9ec4e

Browse files
test: Some ATokenVaultRevenueSplitterOwner tests added - still some core tests missing
1 parent 4a21714 commit af9ec4e

File tree

2 files changed

+338
-0
lines changed

2 files changed

+338
-0
lines changed
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.10;
4+
5+
import "forge-std/Test.sol";
6+
import {MockATokenVault} from "./mocks/MockATokenVault.sol";
7+
import {MockDAI} from "./mocks/MockDAI.sol";
8+
import {ATokenVaultRevenueSplitterOwner} from "../src/ATokenVaultRevenueSplitterOwner.sol";
9+
import {IATokenVault} from "../src/interfaces/IATokenVault.sol";
10+
import {Ownable} from "@openzeppelin/access/Ownable.sol";
11+
12+
contract ATokenVaultRevenueSplitterOwnerTest is Test {
13+
14+
address owner;
15+
16+
MockDAI aToken;
17+
18+
MockDAI rewardAssetI;
19+
MockDAI rewardAssetII;
20+
21+
MockATokenVault vault;
22+
23+
address recipientI;
24+
address recipientII;
25+
address recipientIII;
26+
27+
uint16 shareI;
28+
uint16 shareII;
29+
uint16 shareIII;
30+
31+
ATokenVaultRevenueSplitterOwner.Recipient[] recipients;
32+
33+
ATokenVaultRevenueSplitterOwner revenueSplitterOwner;
34+
35+
function setUp() public {
36+
owner = address(this);
37+
38+
aToken = new MockDAI();
39+
40+
rewardAssetI = new MockDAI();
41+
rewardAssetII = new MockDAI();
42+
43+
vault = new MockATokenVault(address(aToken), owner);
44+
45+
recipientI = makeAddr("recipientI");
46+
recipientII = makeAddr("recipientII");
47+
recipientIII = makeAddr("recipientIII");
48+
49+
shareI = 1000; // 10.00%
50+
shareII = 2000; // 20.00%
51+
shareIII = 7000; // 70.00%
52+
53+
recipients.push(ATokenVaultRevenueSplitterOwner.Recipient({
54+
addr: recipientI,
55+
shareInBps: shareI
56+
}));
57+
recipients.push(ATokenVaultRevenueSplitterOwner.Recipient({
58+
addr: recipientII,
59+
shareInBps: shareII
60+
}));
61+
recipients.push(ATokenVaultRevenueSplitterOwner.Recipient({
62+
addr: recipientIII,
63+
shareInBps: shareIII
64+
}));
65+
66+
revenueSplitterOwner = new ATokenVaultRevenueSplitterOwner(address(vault), owner, recipients);
67+
68+
vault.transferOwnership(address(revenueSplitterOwner));
69+
}
70+
71+
function test_withdrawFees_withdrawsAllFeesToOwnerContract(uint256 amount) public {
72+
vault.mockFees(amount);
73+
74+
assertEq(aToken.balanceOf(address(revenueSplitterOwner)), 0);
75+
76+
vm.expectCall(
77+
address(vault),
78+
abi.encodeWithSelector(IATokenVault.withdrawFees.selector, address(revenueSplitterOwner), amount)
79+
);
80+
revenueSplitterOwner.withdrawFees();
81+
82+
assertEq(aToken.balanceOf(address(revenueSplitterOwner)), amount);
83+
}
84+
85+
function test_withdrawFees_canBeCalledByAnyone(address msgSender, uint256 amount) public {
86+
vault.mockFees(amount);
87+
88+
assertEq(aToken.balanceOf(address(revenueSplitterOwner)), 0);
89+
90+
vm.expectCall(
91+
address(vault),
92+
abi.encodeWithSelector(IATokenVault.withdrawFees.selector, address(revenueSplitterOwner), amount)
93+
);
94+
95+
vm.prank(msgSender);
96+
revenueSplitterOwner.withdrawFees();
97+
98+
assertEq(aToken.balanceOf(address(revenueSplitterOwner)), amount);
99+
}
100+
101+
function test_claimRewards_claimsAllRewardsToOwnerContract(uint256 amountRewardI, uint256 amountRewardII) public {
102+
address[] memory rewardAssets = new address[](2);
103+
rewardAssets[0] = address(rewardAssetI);
104+
rewardAssets[1] = address(rewardAssetII);
105+
106+
uint256[] memory rewardAmounts = new uint256[](2);
107+
rewardAmounts[0] = amountRewardI;
108+
rewardAmounts[1] = amountRewardII;
109+
110+
vault.mockRewards(rewardAssets, rewardAmounts);
111+
112+
assertEq(rewardAssetI.balanceOf(address(revenueSplitterOwner)), 0);
113+
assertEq(rewardAssetII.balanceOf(address(revenueSplitterOwner)), 0);
114+
115+
vm.expectCall(
116+
address(vault),
117+
abi.encodeWithSelector(IATokenVault.claimRewards.selector, address(revenueSplitterOwner))
118+
);
119+
120+
revenueSplitterOwner.claimRewards();
121+
122+
assertEq(rewardAssetI.balanceOf(address(revenueSplitterOwner)), amountRewardI);
123+
assertEq(rewardAssetII.balanceOf(address(revenueSplitterOwner)), amountRewardII);
124+
}
125+
126+
function test_claimRewards_canBeCalledByAnyone(address msgSender, uint256 amountRewardI, uint256 amountRewardII) public {
127+
address[] memory rewardAssets = new address[](2);
128+
rewardAssets[0] = address(rewardAssetI);
129+
rewardAssets[1] = address(rewardAssetII);
130+
131+
uint256[] memory rewardAmounts = new uint256[](2);
132+
rewardAmounts[0] = amountRewardI;
133+
rewardAmounts[1] = amountRewardII;
134+
135+
vault.mockRewards(rewardAssets, rewardAmounts);
136+
137+
assertEq(rewardAssetI.balanceOf(address(revenueSplitterOwner)), 0);
138+
assertEq(rewardAssetII.balanceOf(address(revenueSplitterOwner)), 0);
139+
140+
vm.expectCall(
141+
address(vault),
142+
abi.encodeWithSelector(IATokenVault.claimRewards.selector, address(revenueSplitterOwner))
143+
);
144+
145+
vm.prank(msgSender);
146+
revenueSplitterOwner.claimRewards();
147+
148+
assertEq(rewardAssetI.balanceOf(address(revenueSplitterOwner)), amountRewardI);
149+
assertEq(rewardAssetII.balanceOf(address(revenueSplitterOwner)), amountRewardII);
150+
}
151+
152+
function test_emergencyRescue_nonOwnerCallReverts(
153+
address msgSender,
154+
address assetToRescue,
155+
address to,
156+
uint256 amount
157+
) public {
158+
vm.assume(msgSender != owner);
159+
160+
vm.prank(msgSender);
161+
vm.expectRevert("Ownable: caller is not the owner");
162+
revenueSplitterOwner.emergencyRescue(assetToRescue, to, amount);
163+
}
164+
165+
function test_emergencyRescue(address assetToRescue, address to, uint256 amount) public {
166+
vm.expectCall(
167+
address(vault),
168+
abi.encodeWithSelector(IATokenVault.emergencyRescue.selector, assetToRescue, to, amount)
169+
);
170+
171+
revenueSplitterOwner.emergencyRescue(assetToRescue, to, amount);
172+
}
173+
174+
function test_setFee_nonOwnerCallReverts(address msgSender, uint256 newFee) public {
175+
vm.assume(msgSender != owner);
176+
177+
vm.prank(msgSender);
178+
vm.expectRevert("Ownable: caller is not the owner");
179+
revenueSplitterOwner.setFee(newFee);
180+
}
181+
182+
function test_setFee(uint256 newFee) public {
183+
vm.expectCall(
184+
address(vault),
185+
abi.encodeWithSelector(IATokenVault.setFee.selector, newFee)
186+
);
187+
188+
revenueSplitterOwner.setFee(newFee);
189+
}
190+
191+
function test_transferVaultOwnership_nonOwnerCallReverts(address msgSender, address newVaultOwner) public {
192+
vm.assume(newVaultOwner != address(0));
193+
vm.assume(msgSender != owner);
194+
195+
vm.prank(msgSender);
196+
vm.expectRevert("Ownable: caller is not the owner");
197+
revenueSplitterOwner.transferVaultOwnership(newVaultOwner);
198+
}
199+
200+
function test_transferVaultOwnership_setsTheRightNewVaultOwner(address newVaultOwner) public {
201+
vm.assume(newVaultOwner != address(0));
202+
203+
vm.expectCall(
204+
address(vault),
205+
abi.encodeWithSelector(Ownable.transferOwnership.selector, newVaultOwner)
206+
);
207+
208+
revenueSplitterOwner.transferVaultOwnership(newVaultOwner);
209+
210+
assertEq(Ownable(address(vault)).owner(), newVaultOwner);
211+
}
212+
213+
function test_transferVaultOwnership_claimRewardsAndWithdrawFees(
214+
address newVaultOwner,
215+
uint256 feesToWithdraw,
216+
uint256 rewardsToClaimI,
217+
uint256 rewardsToClaimII
218+
) public {
219+
vm.assume(newVaultOwner != address(0));
220+
221+
vault.mockFees(feesToWithdraw);
222+
223+
address[] memory rewardAssets = new address[](2);
224+
rewardAssets[0] = address(rewardAssetI);
225+
rewardAssets[1] = address(rewardAssetII);
226+
uint256[] memory rewardAmounts = new uint256[](2);
227+
rewardAmounts[0] = rewardsToClaimI;
228+
rewardAmounts[1] = rewardsToClaimII;
229+
vault.mockRewards(rewardAssets, rewardAmounts);
230+
231+
vm.expectCall(
232+
address(vault),
233+
abi.encodeWithSelector(Ownable.transferOwnership.selector, newVaultOwner)
234+
);
235+
236+
vm.expectCall(
237+
address(vault),
238+
abi.encodeWithSelector(IATokenVault.claimRewards.selector, address(revenueSplitterOwner))
239+
);
240+
241+
vm.expectCall(
242+
address(vault),
243+
abi.encodeWithSelector(IATokenVault.withdrawFees.selector, address(revenueSplitterOwner), feesToWithdraw)
244+
);
245+
246+
assertEq(rewardAssetI.balanceOf(address(revenueSplitterOwner)), 0);
247+
assertEq(rewardAssetII.balanceOf(address(revenueSplitterOwner)), 0);
248+
assertEq(aToken.balanceOf(address(revenueSplitterOwner)), 0);
249+
250+
revenueSplitterOwner.transferVaultOwnership(newVaultOwner);
251+
252+
assertEq(Ownable(address(vault)).owner(), newVaultOwner);
253+
assertEq(rewardAssetI.balanceOf(address(revenueSplitterOwner)), rewardsToClaimI);
254+
assertEq(rewardAssetII.balanceOf(address(revenueSplitterOwner)), rewardsToClaimII);
255+
assertEq(aToken.balanceOf(address(revenueSplitterOwner)), feesToWithdraw);
256+
}
257+
258+
function test_transferOwnership_nonOwnerCallReverts(address msgSender, address newOwner) public {
259+
vm.assume(newOwner != address(0));
260+
vm.assume(msgSender != owner);
261+
262+
vm.prank(msgSender);
263+
vm.expectRevert("Ownable: caller is not the owner");
264+
revenueSplitterOwner.transferOwnership(newOwner);
265+
266+
assertEq(revenueSplitterOwner.owner(), owner);
267+
}
268+
269+
function test_transferOwnership(address newOwner) public {
270+
vm.assume(newOwner != address(0));
271+
272+
revenueSplitterOwner.transferOwnership(newOwner);
273+
274+
assertEq(revenueSplitterOwner.owner(), newOwner);
275+
}
276+
}

test/mocks/MockATokenVault.sol

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
import {MockDAI} from "./MockDAI.sol";
4+
import {Ownable} from "@openzeppelin/access/Ownable.sol";
5+
6+
pragma solidity ^0.8.10;
7+
8+
contract MockATokenVault is Ownable {
9+
10+
address internal _aTokenMock;
11+
12+
uint256 internal _fees;
13+
14+
address[] internal _rewardAssets;
15+
uint256[] internal _rewardAmounts;
16+
17+
constructor(address aTokenMock, address owner) Ownable() {
18+
_aTokenMock = aTokenMock;
19+
_transferOwnership(owner);
20+
}
21+
22+
fallback() external payable {}
23+
24+
receive() external payable {}
25+
26+
// Mock functions
27+
28+
function mockFees(uint256 amount) external {
29+
_fees = amount;
30+
// Ensure the vault has enough aTokens to transfer fees later
31+
MockDAI(_aTokenMock).mint(address(this), amount);
32+
}
33+
34+
function mockRewards(address[] calldata mockAssets, uint256[] calldata amounts) external {
35+
require(mockAssets.length == amounts.length, "ARRAY_LENGTH_MISMATCH");
36+
_rewardAssets = mockAssets;
37+
_rewardAmounts = amounts;
38+
for (uint256 i = 0; i < mockAssets.length; i++) {
39+
// Ensure the vault has enough reward mockAssets to transfer them later
40+
MockDAI(mockAssets[i]).mint(address(this), amounts[i]);
41+
}
42+
}
43+
44+
// Relevant aToken Vault functions to implement in the mock
45+
46+
function claimRewards(address to) external onlyOwner {
47+
for (uint256 i = 0; i < _rewardAssets.length; i++) {
48+
MockDAI(_rewardAssets[i]).transfer(to, _rewardAmounts[i]);
49+
}
50+
_rewardAssets = new address[](0);
51+
_rewardAmounts = new uint256[](0);
52+
}
53+
54+
function withdrawFees(address to, uint256 amount) external onlyOwner {
55+
_fees -= amount;
56+
MockDAI(_aTokenMock).transfer(to, amount);
57+
}
58+
59+
function getClaimableFees() external view returns (uint256) {
60+
return _fees;
61+
}
62+
}

0 commit comments

Comments
 (0)