@@ -3,6 +3,7 @@ pragma solidity 0.8.20;
33
44import "forge-std/Test.sol " ;
55import "@openzeppelin/contracts/token/ERC20/ERC20.sol " ;
6+ import "@openzeppelin/contracts/interfaces/draft-IERC6093.sol " ;
67import "../src/FlowYieldVaultsRequests.sol " ;
78
89contract MockDAI is ERC20 {
@@ -1542,6 +1543,11 @@ contract FlowYieldVaultsRequestsTest is Test {
15421543 vm.prank (coa);
15431544 vm.expectRevert (FlowYieldVaultsRequests.MsgValueMustBeZero.selector );
15441545 c.completeProcessing {value: 5 ether }(req2, false , 101 , "Failed " );
1546+
1547+ // Success case must also reject non-zero msg.value (the `else` branch)
1548+ vm.prank (coa);
1549+ vm.expectRevert (FlowYieldVaultsRequests.MsgValueMustBeZero.selector );
1550+ c.completeProcessing {value: 1 ether }(req2, true , 101 , "Success " );
15451551 }
15461552
15471553 function test_CompleteProcessing_RefundNativeFunds () public {
@@ -1580,9 +1586,6 @@ contract FlowYieldVaultsRequestsTest is Test {
15801586 assertEq (dai.balanceOf (user), 20 ether);
15811587 assertEq (dai.balanceOf (address (c)), 0 ether);
15821588
1583- vm.prank (c.owner ());
1584- c.setTokenConfig (address (dai), true , 0.5 ether, false );
1585-
15861589 vm.startPrank (user);
15871590 dai.approve (address (c), 5 ether);
15881591 uint256 reqId = c.createYieldVault (address (dai), 5 ether, VAULT_ID, STRATEGY_ID);
@@ -1597,7 +1600,7 @@ contract FlowYieldVaultsRequestsTest is Test {
15971600
15981601 vm.startPrank (coa);
15991602 dai.approve (address (c), 5 ether);
1600- c.completeProcessing (reqId, false , 101 , "Failed " );
1603+ c.completeProcessing (reqId, false , c. NO_YIELDVAULT_ID () , "Failed " );
16011604 assertEq (dai.balanceOf (coa), 0 ether);
16021605 assertEq (dai.balanceOf (address (c)), 5 ether);
16031606 vm.stopPrank ();
@@ -1627,4 +1630,215 @@ contract FlowYieldVaultsRequestsTest is Test {
16271630 assertEq (dai.balanceOf (address (c)), 0 ether);
16281631 vm.stopPrank ();
16291632 }
1633+
1634+ function test_RecoverTokens_RevertInsufficientRecoveryAmount () public {
1635+ deal (address (dai), user2, 20 ether);
1636+ assertEq (dai.balanceOf (user2), 20 ether);
1637+
1638+ vm.startPrank (user2);
1639+ dai.transfer (address (c), 5 ether);
1640+ assertEq (dai.balanceOf (user2), 15 ether);
1641+ assertEq (dai.balanceOf (address (c)), 5 ether);
1642+ vm.stopPrank ();
1643+
1644+ vm.prank (c.owner ());
1645+ vm.expectRevert (abi.encodeWithSelector (
1646+ FlowYieldVaultsRequests.InsufficientRecoveryAmount.selector ,
1647+ 5 ether,
1648+ 25 ether
1649+ ));
1650+ c.recoverTokens (user2, address (dai), 25 ether);
1651+ }
1652+
1653+ function test_RecoverTokens_RevertInvalidRecoveryUserAddress () public {
1654+ vm.prank (c.owner ());
1655+ vm.expectRevert (FlowYieldVaultsRequests.InvalidRecoveryUserAddress.selector );
1656+ c.recoverTokens (address (0 ), address (dai), 25 ether);
1657+ }
1658+
1659+ function test_RecoverTokens_RevertInvalidRecoveryTokenAddress () public {
1660+ vm.prank (c.owner ());
1661+ vm.expectRevert (FlowYieldVaultsRequests.InvalidRecoveryTokenAddress.selector );
1662+ c.recoverTokens (user2, NATIVE_FLOW, 25 ether);
1663+ }
1664+
1665+ function test_RecoverTokens_WithPendingUserBalanceAndNoExcessAmount () public {
1666+ vm.prank (c.owner ());
1667+ c.testRegisterYieldVaultId (101 , user, address (dai));
1668+ c.setTokenConfig (address (dai), true , 0.5 ether, false );
1669+
1670+ deal (address (dai), user, 20 ether);
1671+ assertEq (dai.balanceOf (user), 20 ether);
1672+ assertEq (dai.balanceOf (address (c)), 0 ether);
1673+
1674+ vm.startPrank (user);
1675+ dai.approve (address (c), 5 ether);
1676+ uint256 reqId = c.createYieldVault (address (dai), 5 ether, VAULT_ID, STRATEGY_ID);
1677+ assertEq (dai.balanceOf (user), 15 ether);
1678+ assertEq (dai.balanceOf (address (c)), 5 ether);
1679+ vm.stopPrank ();
1680+
1681+ vm.prank (c.owner ());
1682+ vm.expectRevert (abi.encodeWithSelector (
1683+ FlowYieldVaultsRequests.InsufficientRecoveryAmount.selector ,
1684+ 0 ether,
1685+ 5 ether
1686+ ));
1687+ c.recoverTokens (user, address (dai), 5 ether);
1688+ }
1689+
1690+ function test_RecoverTokens_WithCancelledRequestAndNoExcessAmount () public {
1691+ vm.prank (c.owner ());
1692+ c.testRegisterYieldVaultId (101 , user, address (dai));
1693+ c.setTokenConfig (address (dai), true , 0.5 ether, false );
1694+
1695+ deal (address (dai), user, 20 ether);
1696+ assertEq (dai.balanceOf (user), 20 ether);
1697+ assertEq (dai.balanceOf (address (c)), 0 ether);
1698+
1699+ vm.startPrank (user);
1700+ dai.approve (address (c), 5 ether);
1701+ uint256 reqId = c.createYieldVault (address (dai), 5 ether, VAULT_ID, STRATEGY_ID);
1702+ assertEq (dai.balanceOf (user), 15 ether);
1703+ assertEq (dai.balanceOf (address (c)), 5 ether);
1704+
1705+ c.cancelRequest (reqId);
1706+ vm.stopPrank ();
1707+
1708+ vm.prank (c.owner ());
1709+ vm.expectRevert (abi.encodeWithSelector (
1710+ FlowYieldVaultsRequests.InsufficientRecoveryAmount.selector ,
1711+ 0 ether,
1712+ 5 ether
1713+ ));
1714+ c.recoverTokens (user, address (dai), 5 ether);
1715+ }
1716+
1717+ function test_RecoverTokens_WithClaimableRefundAndNoExcessAmount () public {
1718+ vm.prank (c.owner ());
1719+ c.testRegisterYieldVaultId (101 , user, address (dai));
1720+ c.setTokenConfig (address (dai), true , 0.5 ether, false );
1721+
1722+ deal (address (dai), user, 20 ether);
1723+ assertEq (dai.balanceOf (user), 20 ether);
1724+ assertEq (dai.balanceOf (address (c)), 0 ether);
1725+
1726+ vm.startPrank (user);
1727+ dai.approve (address (c), 5 ether);
1728+ uint256 reqId = c.createYieldVault (address (dai), 5 ether, VAULT_ID, STRATEGY_ID);
1729+ assertEq (dai.balanceOf (user), 15 ether);
1730+ assertEq (dai.balanceOf (address (c)), 5 ether);
1731+ vm.stopPrank ();
1732+
1733+ vm.prank (coa);
1734+ _startProcessingBatch (reqId);
1735+ assertEq (dai.balanceOf (coa), 5 ether);
1736+ assertEq (dai.balanceOf (address (c)), 0 ether);
1737+
1738+ vm.startPrank (coa);
1739+ dai.approve (address (c), 5 ether);
1740+ c.completeProcessing (reqId, false , c.NO_YIELDVAULT_ID (), "Failed " );
1741+ assertEq (dai.balanceOf (coa), 0 ether);
1742+ assertEq (dai.balanceOf (address (c)), 5 ether);
1743+ vm.stopPrank ();
1744+
1745+ vm.prank (c.owner ());
1746+ vm.expectRevert (abi.encodeWithSelector (
1747+ FlowYieldVaultsRequests.InsufficientRecoveryAmount.selector ,
1748+ 0 ether,
1749+ 5 ether
1750+ ));
1751+ c.recoverTokens (user, address (dai), 5 ether);
1752+ }
1753+
1754+ function test_RecoverTokens_WithProcessingRequestAndExcessAmount () public {
1755+ vm.prank (c.owner ());
1756+ c.testRegisterYieldVaultId (101 , user, address (dai));
1757+ c.setTokenConfig (address (dai), true , 0.5 ether, false );
1758+
1759+ deal (address (dai), user, 20 ether);
1760+ assertEq (dai.balanceOf (user), 20 ether);
1761+ assertEq (dai.balanceOf (address (c)), 0 ether);
1762+
1763+ vm.startPrank (user);
1764+ dai.approve (address (c), 5 ether);
1765+ uint256 reqId = c.createYieldVault (address (dai), 5 ether, VAULT_ID, STRATEGY_ID);
1766+ assertEq (dai.balanceOf (user), 15 ether);
1767+ assertEq (dai.balanceOf (address (c)), 5 ether);
1768+ vm.stopPrank ();
1769+
1770+ vm.prank (coa);
1771+ _startProcessingBatch (reqId);
1772+ assertEq (dai.balanceOf (coa), 5 ether);
1773+ assertEq (dai.balanceOf (address (c)), 0 ether);
1774+
1775+ vm.prank (user);
1776+ dai.transfer (address (c), 3 ether);
1777+
1778+ vm.prank (c.owner ());
1779+ c.recoverTokens (user, address (dai), 3 ether);
1780+ assertEq (dai.balanceOf (address (c)), 0 ether);
1781+ assertEq (dai.balanceOf (user), 15 ether);
1782+ }
1783+
1784+ function test_RecoverTokens_RevertWhenAccountedExceedsAmount () public {
1785+ c.testRegisterYieldVaultId (101 , user, address (dai));
1786+ c.setTokenConfig (address (dai), true , 0.5 ether, false );
1787+ deal (address (dai), user, 20 ether);
1788+ vm.startPrank (user);
1789+ dai.approve (address (c), 5 ether);
1790+ c.createYieldVault (address (dai), 5 ether, VAULT_ID, STRATEGY_ID);
1791+ vm.stopPrank ();
1792+
1793+ // contract has a balance of 5 DAI via the above createYieldVault,
1794+ // but there is no excess balance for the given token.
1795+ vm.prank (c.owner ());
1796+ vm.expectRevert (abi.encodeWithSelector (
1797+ FlowYieldVaultsRequests.InsufficientRecoveryAmount.selector ,
1798+ 0 ,
1799+ 3 ether
1800+ ));
1801+ c.recoverTokens (user, address (dai), 3 ether);
1802+ }
1803+
1804+ function test_RecoverTokens_WithAccountedLessThanAmount () public {
1805+ c.testRegisterYieldVaultId (101 , user, address (dai));
1806+ c.setTokenConfig (address (dai), true , 0.5 ether, false );
1807+ deal (address (dai), user, 20 ether);
1808+ vm.startPrank (user);
1809+ dai.approve (address (c), 5 ether);
1810+ c.createYieldVault (address (dai), 5 ether, VAULT_ID, STRATEGY_ID);
1811+ vm.stopPrank ();
1812+
1813+ vm.prank (user);
1814+ dai.transfer (address (c), 8 ether);
1815+ assertEq (dai.balanceOf (address (c)), 13 ether);
1816+
1817+ // contract has 5 ether in pendingUserBalances via createYieldVault
1818+ vm.prank (c.owner ());
1819+ c.recoverTokens (user, address (dai), 8 ether);
1820+ // user still has 5 ether in pendingUserBalances via createYieldVault,
1821+ // even after the stray token recovery
1822+ assertEq (c.getUserPendingBalance (user, address (dai)), 5 ether);
1823+ assertEq (dai.balanceOf (address (c)), 5 ether);
1824+ }
1825+
1826+ function test_RecoverTokens_RevertWhenNotOwner () public {
1827+ deal (address (dai), user2, 5 ether);
1828+ vm.prank (user2);
1829+ dai.transfer (address (c), 5 ether);
1830+
1831+ vm.prank (user2); // non-owner
1832+ vm.expectRevert (abi.encodeWithSelector (
1833+ OwnableUnauthorizedAccount.selector ,
1834+ user2
1835+ ));
1836+ c.recoverTokens (user2, address (dai), 5 ether);
1837+ }
1838+
1839+ function test_RecoverTokens_RevertInvalidRecoveryUserAddress_ContractSelf () public {
1840+ vm.prank (c.owner ());
1841+ vm.expectRevert (FlowYieldVaultsRequests.InvalidRecoveryUserAddress.selector );
1842+ c.recoverTokens (address (c), address (dai), 1 ether);
1843+ }
16301844}
0 commit comments