fluid-contracts-public/test/foundry/periphery/wallet/walletFactory.t.sol

340 lines
13 KiB
Solidity

//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import "forge-std/Test.sol";
import "forge-std/console2.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { LiquidityBaseTest } from "../../liquidity/liquidityBaseTest.t.sol";
import { IFluidLiquidityLogic } from "../../../../contracts/liquidity/interfaces/iLiquidity.sol";
import { FluidVaultT1 } from "../../../../contracts/protocols/vault/vaultT1/coreModule/main.sol";
import { FluidVaultT1Admin } from "../../../../contracts/protocols/vault/vaultT1/adminModule/main.sol";
import { MockOracle } from "../../../../contracts/mocks/mockOracle.sol";
import { VaultFactoryTest } from "../../vaultT1/factory/vaultFactory.t.sol";
import { VaultT1BaseTest } from "../../vaultT1/vault/vault.t.sol";
import { FluidLiquidityResolver } from "../../../../contracts/periphery/resolvers/liquidity/main.sol";
import { FluidVaultResolver } from "../../../../contracts/periphery/resolvers/vault/main.sol";
import { IFluidLiquidity } from "../../../../contracts/liquidity/interfaces/iLiquidity.sol";
import { FluidVaultFactory } from "../../../../contracts/protocols/vault/factory/main.sol";
import { TickMath } from "../../../../contracts/libraries/tickMath.sol";
import { LiquidityCalcs } from "../../../../contracts/libraries/liquidityCalcs.sol";
import { Structs as VaultStructs } from "../../../../contracts/periphery/resolvers/vault/structs.sol";
import "../../testERC20.sol";
import "../../testERC20Dec6.sol";
import { FluidLendingRewardsRateModel } from "../../../../contracts/protocols/lending/lendingRewardsRateModel/main.sol";
import { ErrorTypes } from "../../../../contracts/protocols/vault/errorTypes.sol";
import { Error } from "../../../../contracts/protocols/vault/error.sol";
import { MockFLA } from "../../../../contracts/mocks/mockFLA.sol";
import { MockSwap } from "../../../../contracts/mocks/mockSwap.sol";
import { MockWETH } from "../../../../contracts/mocks/mockWETH.sol";
import { FluidWalletFactory } from "../../../../contracts/periphery/wallet/factory/main.sol";
import { FluidWalletFactoryProxy } from "../../../../contracts/periphery/wallet/factory/proxy.sol";
import { FluidWalletImplementation, FluidWalletErrorsAndEvents } from "../../../../contracts/periphery/wallet/wallet/main.sol";
import { FluidWallet } from "../../../../contracts/periphery/wallet/wallet/proxy.sol";
interface InstaFlashInterface {
function flashLoan(address[] memory tokens, uint256[] memory amts, uint route, bytes memory data, bytes memory extraData) external;
}
contract FluidWalletFactoryTest is VaultT1BaseTest {
using stdStorage for StdStorage;
FluidWalletFactory fluidWalletFactory;
FluidWalletFactory fluidWalletFactoryImplementation;
FluidWalletImplementation fluidWalletImplementation;
MockWETH wETH;
MockFLA fla;
MockSwap swapAggr;
function setUp() public virtual override {
super.setUp();
wETH = new MockWETH();
fla = new MockFLA();
swapAggr = new MockSwap();
vm.startPrank(bob);
FluidWalletFactoryProxy proxy = new FluidWalletFactoryProxy(
address(new FluidWalletFactory(address(vaultFactory), address(0))),
abi.encode()
);
fluidWalletFactory = FluidWalletFactory(payable(proxy));
fluidWalletFactory.initialize(address(bob));
fluidWalletFactoryImplementation = new FluidWalletFactory(address(vaultFactory), address(proxy));
FluidWalletFactory(payable(proxy)).upgradeTo(address(fluidWalletFactoryImplementation));
fluidWalletImplementation = new FluidWalletImplementation(
address(vaultFactory),
address(proxy)
);
fluidWalletFactory.changeImplementation(address(fluidWalletImplementation));
vm.stopPrank();
assertNotEq(fluidWalletFactory.walletImplementation(), address(0));
TestERC20(address(DAI)).mint(address(fla), 1e50 ether);
TestERC20(address(DAI)).mint(address(swapAggr), 1e50 ether);
TestERC20(address(USDC)).mint(address(fla), 1e50 ether);
TestERC20(address(USDC)).mint(address(swapAggr), 1e50 ether);
// TestERC20(address(DAI)).mint(address(vaultT1Migrator), 1e50 ether);
// TestERC20(address(USDC)).mint(address(vaultT1Migrator), 1e50 ether);
vm.deal(alice, 1e7 ether);
vm.startPrank(alice);
wETH.deposit{ value: 1e6 ether }();
wETH.transfer(address(fla), 1e5 ether);
wETH.transfer(address(swapAggr), 100 ether);
vm.stopPrank();
vm.deal(address(swapAggr), 1e50 ether);
// vm.deal(address(vaultT1Migrator), 1e20 ether);
}
function testFailUpgradableOfImplementationNonOwner() public {
address fluidWalletFactoryImplementationNew = address(new FluidWalletFactory(address(vaultFactory), address(fluidWalletFactory)));
vm.prank(alice);
fluidWalletFactory.upgradeTo(fluidWalletFactoryImplementationNew);
}
function testUpgradableOfImplementation() public {
address fluidWalletFactoryImplementationNew = address(new FluidWalletFactory(address(vaultFactory), address(fluidWalletFactory)));
vm.prank(bob);
fluidWalletFactory.upgradeTo(fluidWalletFactoryImplementationNew);
}
function testDeploymentOfWallet() public {
address wallet_ = fluidWalletFactory.deploy(address(alice));
assertEq(wallet_, fluidWalletFactory.computeWallet(address(alice)));
}
function testSimpleERC20Actions() public {
address wallet_ = fluidWalletFactory.deploy(address(alice));
FluidWalletImplementation.Action[] memory actions_ = new FluidWalletImplementation.Action[](1);
actions_[0] = FluidWalletErrorsAndEvents.Action({
target: address(DAI),
data: abi.encodeWithSignature("transfer(address,uint256)", alice, 1e18),
operation: 0,
value: 0
});
TestERC20(address(DAI)).mint(address(wallet_), 1e50 ether);
vm.prank(alice);
FluidWalletImplementation(wallet_).cast(actions_);
}
function testFailFlashloanActionsDueToOperation() public {
address wallet_ = fluidWalletFactory.deploy(address(alice));
FluidWalletImplementation.Action[] memory actions_ = new FluidWalletImplementation.Action[](1);
address[] memory tokens_ = new address[](1);
uint256[] memory amounts_ = new uint256[](1);
FluidWalletImplementation.Action[] memory flashloanActions_ = new FluidWalletImplementation.Action[](1);
flashloanActions_[0] = FluidWalletErrorsAndEvents.Action({
target: address(DAI),
data: abi.encodeWithSignature("transfer(address,uint256)", address(fla), 10 ether),
operation: 0,
value: 0
});
tokens_[0] = address(DAI);
amounts_[0] = 10 ether;
actions_[0] = FluidWalletErrorsAndEvents.Action({
target: address(fla),
data: abi.encodeWithSelector(
InstaFlashInterface.flashLoan.selector,
tokens_,
amounts_,
5,
abi.encode(flashloanActions_),
abi.encode()
),
operation: 0,
value: 0
});
TestERC20(address(DAI)).mint(address(wallet_), 1e50 ether);
vm.prank(alice);
FluidWalletImplementation(wallet_).cast(actions_);
}
function testFlashloanActions() public {
address wallet_ = fluidWalletFactory.deploy(address(alice));
FluidWalletImplementation.Action[] memory actions_ = new FluidWalletImplementation.Action[](1);
address[] memory tokens_ = new address[](1);
uint256[] memory amounts_ = new uint256[](1);
FluidWalletImplementation.Action[] memory flashloanActions_ = new FluidWalletImplementation.Action[](1);
flashloanActions_[0] = FluidWalletErrorsAndEvents.Action({
target: address(DAI),
data: abi.encodeWithSignature("transfer(address,uint256)", address(fla), 10 ether),
operation: 0,
value: 0
});
tokens_[0] = address(DAI);
amounts_[0] = 10 ether;
actions_[0] = FluidWalletErrorsAndEvents.Action({
target: address(fla),
data: abi.encodeWithSelector(
InstaFlashInterface.flashLoan.selector,
tokens_,
amounts_,
5,
abi.encode(flashloanActions_),
abi.encode()
),
operation: 2,
value: 0
});
TestERC20(address(DAI)).mint(address(wallet_), 1e50 ether);
vm.prank(alice);
FluidWalletImplementation(wallet_).cast(actions_);
assertEq(uint256(vm.load(wallet_, bytes32(uint256(1)))), 1);
}
function testVaultOperation() public {
address wallet_ = fluidWalletFactory.computeWallet(address(alice));
int collateral = 10_000 * 1e18;
int debt = 7000 * 1e6;
uint oraclePrice = (1e27 * (1 * 1e6)) / (1 * 1e18); // 1 DAI = 1 USDC
_setOracleTwoPrice(oraclePrice);
vm.prank(alice);
(uint256 nftId_, ,) = vaultTwo.operate(
0,
collateral,
debt,
alice
);
FluidWalletImplementation.Action[] memory actions_ = new FluidWalletImplementation.Action[](2);
actions_[0] = FluidWalletErrorsAndEvents.Action({
target: address(DAI),
data: abi.encodeWithSignature(
"approve(address,uint256)",
address(vaultTwo),
uint256(collateral)
),
operation: 0,
value: 0
});
actions_[1] = FluidWalletErrorsAndEvents.Action({
target: address(vaultTwo),
data: abi.encodeWithSelector(
vaultTwo.operate.selector,
nftId_,
collateral,
debt,
wallet_
),
operation: 0,
value: 0
});
TestERC20(address(DAI)).mint(address(wallet_), 1e50 ether);
vm.prank(alice);
vaultFactory.safeTransferFrom(
alice,
address(fluidWalletFactory),
nftId_,
abi.encode(actions_)
);
assertEq(vaultFactory.ownerOf(nftId_), alice, "Owner-of-nft-is-not-alice");
assertEq(vaultFactory.balanceOf(wallet_), 0, "wallet-of-balance-is-not");
assertEq(DAI.balanceOf(wallet_), 0, "DAI-balance-is-not-zero");
assertEq(USDC.balanceOf(wallet_), 0, "USDC-balance-is-not-zero");
assertEq(uint256(vm.load(wallet_, bytes32(uint256(1)))), 1);
assertEq(vaultFactory.ownerOf(nftId_), alice);
}
function testVaultOperationNativeDebt() public {
address wallet_ = fluidWalletFactory.computeWallet(address(alice));
int collateral = 10_000 * 1e6;
int debt = 3.995 * 1e18;
uint oraclePrice = (1e27 * (1 * 1e18)) / (2000 * 1e6); // 1 ETH = 2000 USDC => 1 USDC => 1/2000 ETH
// 1e27 * 1 * 1e18 / 2000 * 1e6
_setOracleFourPrice(oraclePrice);
vm.prank(alice);
(uint256 nftId_, , ) = vaultFour.operate(
0, // new position
collateral,
debt,
alice
);
FluidWalletImplementation.Action[] memory actions_ = new FluidWalletImplementation.Action[](2);
actions_[0] = FluidWalletErrorsAndEvents.Action({
target: address(USDC),
data: abi.encodeWithSignature(
"approve(address,uint256)",
address(vaultFour),
uint256(collateral)
),
operation: 0,
value: 0
});
actions_[1] = FluidWalletErrorsAndEvents.Action({
target: address(vaultFour),
data: abi.encodeWithSelector(
vaultFour.operate.selector,
nftId_,
collateral,
debt,
wallet_
),
operation: 0,
value: 0
});
TestERC20(address(USDC)).mint(address(wallet_), 1e50 * 1e6);
vm.prank(alice);
vaultFactory.safeTransferFrom(
alice,
address(fluidWalletFactory),
nftId_,
abi.encode(actions_)
);
assertEq(vaultFactory.ownerOf(nftId_), alice, "Owner-of-nft-is-not-alice");
assertEq(vaultFactory.balanceOf(wallet_), 0, "wallet-of-balance-is-not");
assertEq(USDC.balanceOf(wallet_), 0, "USDC-balance-is-not-zero");
assertEq(wallet_.balance, 0, "ETH-balance-is-not-zero");
assertEq(uint256(vm.load(wallet_, bytes32(uint256(1)))), 1);
assertEq(vaultFactory.ownerOf(nftId_), alice);
}
}