diff --git a/test/fork/UseCases.fork.t.sol b/test/fork/UseCases.fork.t.sol index 93ae7a4..84c8823 100644 --- a/test/fork/UseCases.fork.t.sol +++ b/test/fork/UseCases.fork.t.sol @@ -4,8 +4,6 @@ pragma solidity 0.8.16; import { MultiToken, ICryptoKitties, IERC20, IERC721 } from "MultiToken/MultiToken.sol"; import { Permit } from "src/loan/vault/Permit.sol"; -import { CompoundAdapter } from "src/pool-adapter/CompoundAdapter.sol"; -import { UniV3PosStateFingerpringComputer } from "src/state-fingerprint-computer/UniV3PosStateFingerpringComputer.sol"; import "src/PWNErrors.sol"; import { T20 } from "test/helper/T20.sol"; @@ -376,269 +374,3 @@ contract CategoryRegistryForIncompleteERCTokensTest is UseCasesTest { } } - - -interface UniV3PostLike { - struct DecreaseLiquidityParams { - uint256 tokenId; - uint128 liquidity; - uint256 amount0Min; - uint256 amount1Min; - uint256 deadline; - } - - /// @notice Decreases the amount of liquidity in a position and accounts it to the position - /// @param params tokenId The ID of the token for which liquidity is being decreased, - /// amount The amount by which liquidity will be decreased, - /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity, - /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity, - /// deadline The time by which the transaction must be included to effect the change - /// @return amount0 The amount of token0 accounted to the position's tokens owed - /// @return amount1 The amount of token1 accounted to the position's tokens owed - function decreaseLiquidity(DecreaseLiquidityParams calldata params) - external - payable - returns (uint256 amount0, uint256 amount1); -} - -contract StateFingerprintTest is UseCasesTest { - - address constant UNI_V3_POS = 0xC36442b4a4522E871399CD717aBDD847Ab11FE88; - - function test_shouldFail_whenUniV3PosStateChanges() external { - UniV3PosStateFingerpringComputer computer = new UniV3PosStateFingerpringComputer(UNI_V3_POS); - deployment.config.registerStateFingerprintComputer(UNI_V3_POS, address(computer)); - - uint256 collId = 1; - address originalOwner = IERC721(UNI_V3_POS).ownerOf(collId); - vm.prank(originalOwner); - IERC721(UNI_V3_POS).transferFrom(originalOwner, borrower, collId); - - vm.prank(borrower); - IERC721(UNI_V3_POS).setApprovalForAll(address(deployment.simpleLoan), true); - - // Define proposal - proposal.collateralCategory = MultiToken.Category.ERC721; - proposal.collateralAddress = UNI_V3_POS; - proposal.collateralId = collId; - proposal.collateralAmount = 0; - proposal.checkCollateralStateFingerprint = true; - proposal.collateralStateFingerprint = computer.computeStateFingerprint(UNI_V3_POS, collId); - - vm.prank(borrower); - UniV3PostLike(UNI_V3_POS).decreaseLiquidity(UniV3PostLike.DecreaseLiquidityParams({ - tokenId: collId, - liquidity: 100, - amount0Min: 0, - amount1Min: 0, - deadline: block.timestamp + 1 days - })); - bytes32 currentFingerprint = computer.computeStateFingerprint(UNI_V3_POS, collId); - - assertNotEq(currentFingerprint, proposal.collateralStateFingerprint); - - // Create loan - _createLoanRevertWith( - abi.encodeWithSelector(InvalidCollateralStateFingerprint.selector, currentFingerprint, proposal.collateralStateFingerprint) - ); - } - - function test_shouldPass_whenUniV3PosStateDoesNotChange() external { - UniV3PosStateFingerpringComputer computer = new UniV3PosStateFingerpringComputer(UNI_V3_POS); - deployment.config.registerStateFingerprintComputer(UNI_V3_POS, address(computer)); - - uint256 collId = 1; - address originalOwner = IERC721(UNI_V3_POS).ownerOf(collId); - vm.prank(originalOwner); - IERC721(UNI_V3_POS).transferFrom(originalOwner, borrower, collId); - - vm.prank(borrower); - IERC721(UNI_V3_POS).setApprovalForAll(address(deployment.simpleLoan), true); - - // Define proposal - proposal.collateralCategory = MultiToken.Category.ERC721; - proposal.collateralAddress = UNI_V3_POS; - proposal.collateralId = collId; - proposal.collateralAmount = 0; - proposal.checkCollateralStateFingerprint = true; - proposal.collateralStateFingerprint = computer.computeStateFingerprint(UNI_V3_POS, collId); - - // Create loan - _createLoan(); - - // Check balance - assertEq(IERC721(UNI_V3_POS).ownerOf(collId), address(deployment.simpleLoan)); - } - -} - - -interface ICometLike { - function allow(address manager, bool isAllowed) external; - function supply(address asset, uint amount) external; - function withdraw(address asset, uint amount) external; -} - -contract PoolAdapterTest is UseCasesTest { - - address constant CMP_USDC = 0xc3d688B66703497DAA19211EEdff47f25384cdc3; - address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; - - function test_shouldWithdrawAndRepayToPool() external { - CompoundAdapter adapter = new CompoundAdapter(address(deployment.hub)); - deployment.config.registerPoolAdapter(CMP_USDC, address(adapter)); - - vm.prank(0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503); - IERC20(USDC).transfer(lender, 1000e6); - - // Supply to pool 1k USDC - vm.startPrank(lender); - IERC20(USDC).approve(CMP_USDC, type(uint256).max); - ICometLike(CMP_USDC).supply(USDC, 1000e6); - ICometLike(CMP_USDC).allow(address(adapter), true); - vm.stopPrank(); - - vm.prank(borrower); - IERC20(USDC).approve(address(deployment.simpleLoan), type(uint256).max); - - // Update lender spec - PWNSimpleLoan.LenderSpec memory lenderSpec = PWNSimpleLoan.LenderSpec({ - sourceOfFunds: CMP_USDC - }); - - // Update proposal - proposal.creditAddress = USDC; - proposal.creditAmount = 100e6; // 100 USDC - proposal.proposerSpecHash = deployment.simpleLoan.getLenderSpecHash(lenderSpec); - - assertEq(IERC20(USDC).balanceOf(lender), 0); - assertEq(IERC20(USDC).balanceOf(borrower), 0); - - // Make proposal - vm.prank(lender); - deployment.simpleLoanSimpleProposal.makeProposal(proposal); - - bytes memory proposalData = deployment.simpleLoanSimpleProposal.encodeProposalData(proposal); - - // Create loan - vm.prank(borrower); - uint256 loanId = deployment.simpleLoan.createLOAN({ - proposalSpec: PWNSimpleLoan.ProposalSpec({ - proposalContract: address(deployment.simpleLoanSimpleProposal), - proposalData: proposalData, - proposalInclusionProof: new bytes32[](0), - signature: "" - }), - lenderSpec: lenderSpec, - callerSpec: PWNSimpleLoan.CallerSpec({ - refinancingLoanId: 0, - revokeNonce: false, - nonce: 0, - permitData: "" - }), - extra: "" - }); - - // Check balance - assertEq(IERC20(USDC).balanceOf(lender), 0); - assertEq(IERC20(USDC).balanceOf(borrower), 100e6); - - // Move in time - vm.warp(block.timestamp + 20 hours); - - // Repay loan - vm.prank(borrower); - deployment.simpleLoan.repayLOAN({ - loanId: loanId, - permitData: "" - }); - - // LOAN token owner is original lender -> repay funds to the pool - assertEq(IERC20(USDC).balanceOf(lender), 0); - assertEq(IERC20(USDC).balanceOf(borrower), 0); - vm.expectRevert("ERC721: invalid token ID"); - deployment.loanToken.ownerOf(loanId); - } - - function test_shouldWithdrawFromPoolAndRepayToVault() external { - CompoundAdapter adapter = new CompoundAdapter(address(deployment.hub)); - deployment.config.registerPoolAdapter(CMP_USDC, address(adapter)); - - vm.prank(0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503); - IERC20(USDC).transfer(lender, 1000e6); - - // Supply to pool 1k USDC - vm.startPrank(lender); - IERC20(USDC).approve(CMP_USDC, type(uint256).max); - ICometLike(CMP_USDC).supply(USDC, 1000e6); - ICometLike(CMP_USDC).allow(address(adapter), true); - vm.stopPrank(); - - vm.prank(borrower); - IERC20(USDC).approve(address(deployment.simpleLoan), type(uint256).max); - - // Update lender spec - PWNSimpleLoan.LenderSpec memory lenderSpec = PWNSimpleLoan.LenderSpec({ - sourceOfFunds: CMP_USDC - }); - - // Update proposal - proposal.creditAddress = USDC; - proposal.creditAmount = 100e6; // 100 USDC - proposal.proposerSpecHash = deployment.simpleLoan.getLenderSpecHash(lenderSpec); - - assertEq(IERC20(USDC).balanceOf(lender), 0); - assertEq(IERC20(USDC).balanceOf(borrower), 0); - - // Make proposal - vm.prank(lender); - deployment.simpleLoanSimpleProposal.makeProposal(proposal); - - bytes memory proposalData = deployment.simpleLoanSimpleProposal.encodeProposalData(proposal); - - // Create loan - vm.prank(borrower); - uint256 loanId = deployment.simpleLoan.createLOAN({ - proposalSpec: PWNSimpleLoan.ProposalSpec({ - proposalContract: address(deployment.simpleLoanSimpleProposal), - proposalData: proposalData, - proposalInclusionProof: new bytes32[](0), - signature: "" - }), - lenderSpec: lenderSpec, - callerSpec: PWNSimpleLoan.CallerSpec({ - refinancingLoanId: 0, - revokeNonce: false, - nonce: 0, - permitData: "" - }), - extra: "" - }); - - // Check balance - assertEq(IERC20(USDC).balanceOf(lender), 0); - assertEq(IERC20(USDC).balanceOf(borrower), 100e6); - - // Move in time - vm.warp(block.timestamp + 20 hours); - - address newLender = makeAddr("new lender"); - - vm.prank(lender); - deployment.loanToken.transferFrom(lender, newLender, loanId); - - uint256 originalBalance = IERC20(USDC).balanceOf(address(deployment.simpleLoan)); - - // Repay loan - vm.prank(borrower); - deployment.simpleLoan.repayLOAN({ - loanId: loanId, - permitData: "" - }); - - // LOAN token owner is not original lender -> repay funds to the Vault - assertEq(IERC20(USDC).balanceOf(address(deployment.simpleLoan)), originalBalance + 100e6); - assertEq(deployment.loanToken.ownerOf(loanId), newLender); - } - -}