diff --git a/src/actions/market/marketLeverageBorrowAction/index.ts b/src/actions/market/marketLeverageBorrowAction/index.ts index ee55a44..15d2f6f 100644 --- a/src/actions/market/marketLeverageBorrowAction/index.ts +++ b/src/actions/market/marketLeverageBorrowAction/index.ts @@ -2,8 +2,7 @@ import { DEFAULT_SLIPPAGE_TOLERANCE, MarketId, MathLib } from "@morpho-org/blue- import { fetchMarket } from "@morpho-org/blue-sdk-viem"; import { BundlerAction, BundlerCall, encodeBundle } from "@morpho-org/bundler-sdk-viem"; import { populateSubBundle } from "@morpho-org/bundler-sdk-viem"; -import { Address, Client, erc20Abi, maxUint256 } from "viem"; -import { readContract } from "viem/actions"; +import { Address, Client, maxUint256 } from "viem"; import { getParaswapExactBuyTxPayload } from "@/actions/data/paraswap/getParaswapExactBuy"; import { getIsContract } from "@/actions/data/rpc/getIsContract"; @@ -26,7 +25,7 @@ interface MarketLeveragedBorrowActionParameters { accountAddress: Address; - initialCollateralAmount: bigint; // a.k.a margin, maxUint256 for entire wallet balance + initialCollateralAmount: bigint; // a.k.a margin leverageFactor: number; // (1, (1 + S) / (1 + S - LLTV_WITH_MARGIN))] maxSlippageTolerance: number; // (0,1) } @@ -50,25 +49,23 @@ export async function marketLeveragedBorrowAction({ leverageFactor, maxSlippageTolerance, }: MarketLeveragedBorrowActionParameters): Promise { - // Input validation performed within computeLeverageValues + // Disallow maxUint256, we require exact collateral amount + if (initialCollateralAmount >= maxUint256) { + return { + status: "error", + message: "Initial collateral amount cannot be greater than or equal to max uint256", + }; + } + + // Other input validation performed within computeLeverageValues let market = await fetchMarket(marketId, publicClient); const { collateralToken: collateralTokenAddress, loanToken: loanTokenAddress } = market.params; - const accountCollateralBalance = await readContract(publicClient, { - address: collateralTokenAddress, - abi: erc20Abi, - functionName: "balanceOf", - args: [accountAddress], - }); - - const initialCollateralAmountInternal = - initialCollateralAmount == maxUint256 ? accountCollateralBalance : initialCollateralAmount; - let collateralAmount: bigint; let loanAmount: bigint; try { - const values = computeLeverageValues(initialCollateralAmountInternal, leverageFactor, maxSlippageTolerance, market); + const values = computeLeverageValues(initialCollateralAmount, leverageFactor, maxSlippageTolerance, market); collateralAmount = values.collateralAmount; loanAmount = values.loanAmount; } catch (e) { @@ -96,13 +93,13 @@ export async function marketLeveragedBorrowAction({ const positionLoanBefore = market.toBorrowAssets(accountPosition.borrowShares); const positionLtvBefore = market.getLtv(accountPosition) ?? 0n; - const requiredSwapCollateralAmount = collateralAmount - initialCollateralAmountInternal; + const requiredSwapCollateralAmount = collateralAmount - initialCollateralAmount; try { const inputSubbundle = inputTransferSubbundle({ accountAddress, tokenAddress: collateralTokenAddress, - amount: initialCollateralAmount, // Handles maxUint256 + amount: initialCollateralAmount, recipientAddress: GENERAL_ADAPTER_1_ADDRESS, config: { accountSupportsSignatures: !isContract, diff --git a/src/actions/market/marketRepayWithCollateralAction.ts b/src/actions/market/marketRepayWithCollateralAction.ts index fcc0b1d..cc69d08 100644 --- a/src/actions/market/marketRepayWithCollateralAction.ts +++ b/src/actions/market/marketRepayWithCollateralAction.ts @@ -65,6 +65,8 @@ export async function marketRepayWithCollateralAction({ const market = simulationState.getMarket(marketId); const accountPosition = simulationState.getPosition(accountAddress, marketId); + const accountPositionInitialBorrowShares = accountPosition.borrowShares; + const positionCollateralBefore = accountPosition.collateral; const positionLoanBefore = market.toBorrowAssets(accountPosition.borrowShares); const positionLtvBefore = market.getLtv(accountPosition) ?? 0n; @@ -133,7 +135,7 @@ export async function marketRepayWithCollateralAction({ id: marketId, onBehalf: accountAddress, receiver: PARASWAP_ADAPTER_ADDRESS, - assets: closingPosition ? accountPosition.collateral : maxCollateralSwapAmount, // Full collateral withdraw if closing position - bundler SDK has issues with maxUint256, but this works the same + assets: closingPosition ? accountPosition.collateral : maxCollateralSwapAmount, }, }, simulationState @@ -152,7 +154,7 @@ export async function marketRepayWithCollateralAction({ CHAIN_ID, market.params, closingPosition ? 0n : loanRepayAmount, // Assets - closingPosition ? maxUint256 : 0n, // Shares - full repay using shares when closing position + closingPosition ? accountPositionInitialBorrowShares : 0n, // Shares - full repay using shares when closing position maxSharePriceE27, accountAddress, // Repay loan callbacks, all actions will happen before Morpho pulls the required loan assets from GA1 (i.e must have required loan assets in GA1 at the end of these callbacks) diff --git a/src/actions/subbundles/inputTransferSubbundle.ts b/src/actions/subbundles/inputTransferSubbundle.ts index 9aa577c..5d8844e 100644 --- a/src/actions/subbundles/inputTransferSubbundle.ts +++ b/src/actions/subbundles/inputTransferSubbundle.ts @@ -34,6 +34,13 @@ export function inputTransferSubbundle({ simulationState, }: InputTransferSubbundleParameters): Subbundle & { erc20Amount: bigint; nativeAmount: bigint } { const isMaxTransfer = amount == maxUint256; + + // Sanity check for now to disable maxUint256 input transfer. + // No actions should use anyways. Migration does but is disabled + if(isMaxTransfer) { + throw new Error("Max uint256 transfer is not supported"); + } + const isWrappedNative = isAddressEqual(tokenAddress, WRAPPED_NATIVE_ADDRESS); const accountErc20Holding = simulationState.getHolding(accountAddress, tokenAddress); diff --git a/src/actions/vault/vaultSupplyAction.ts b/src/actions/vault/vaultSupplyAction.ts index cf5aecd..a877302 100644 --- a/src/actions/vault/vaultSupplyAction.ts +++ b/src/actions/vault/vaultSupplyAction.ts @@ -16,7 +16,7 @@ interface VaultSupplyActionParameters { publicClient: Client; vaultAddress: Address; accountAddress: Address; - supplyAmount: bigint; // Max uint256 for entire account balanace + supplyAmount: bigint; allowWrappingNativeAssets: boolean; // Ignored if the vault asset is not wrapped native } @@ -38,6 +38,14 @@ export async function vaultSupplyBundle({ }; } + // Disallow maxUint256 - require exact supply amount + if (supplyAmount >= maxUint256) { + return { + status: "error", + message: "Supply amount cannot be greater than or equal to max uint256", + }; + } + const [intitialSimulationState, accountIsContract] = await Promise.all([ getSimulationState({ actionType: "vault", @@ -50,8 +58,6 @@ export async function vaultSupplyBundle({ const vault = intitialSimulationState.getVault(vaultAddress); - const isMaxSupply = supplyAmount === maxUint256; - try { const intermediateSimulationState = produceImmutable(intitialSimulationState, () => {}); @@ -59,7 +65,7 @@ export async function vaultSupplyBundle({ const inputSubbundle = inputTransferSubbundle({ accountAddress, tokenAddress: vault.underlying, - amount: supplyAmount, // Handles maxUint256 + amount: supplyAmount, recipientAddress: GENERAL_ADAPTER_1_ADDRESS, config: { accountSupportsSignatures: !accountIsContract, @@ -69,8 +75,6 @@ export async function vaultSupplyBundle({ simulationState: intermediateSimulationState, }); - const ga1AssetBalance = intermediateSimulationState.getHolding(GENERAL_ADAPTER_1_ADDRESS, vault.asset).balance; - const vaultSupplySubbundle = subbundleFromInputOps({ inputOps: [ { @@ -78,7 +82,7 @@ export async function vaultSupplyBundle({ sender: accountAddress, address: vaultAddress, args: { - assets: isMaxSupply ? ga1AssetBalance : supplyAmount, + assets: supplyAmount, owner: accountAddress, slippage: DEFAULT_SLIPPAGE_TOLERANCE, }, diff --git a/src/app/migrate/page.tsx b/src/app/migrate/page.tsx index 5079a12..a5bdf51 100644 --- a/src/app/migrate/page.tsx +++ b/src/app/migrate/page.tsx @@ -1,12 +1,6 @@ import { Metadata } from "next"; import Image from "next/image"; -import PositionMigrator from "@/components/PositionMigrator"; -import ProtocolMigratorTableWrapper from "@/components/ProtocolMigrator/ProtocolMigratorTableWrapper"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { MarketSummary, getMarketSummaries } from "@/data/whisk/getMarketSummaries"; -import { getVaultSummaries } from "@/data/whisk/getVaultSummaries"; - export const metadata: Metadata = { title: "Compound Blue | Migrate", }; @@ -24,7 +18,9 @@ export default function MigratePage() { - +
Migration is currently unavailable.
+ + {/* Protocol Position @@ -39,19 +35,19 @@ export default function MigratePage() { - +
*/} ); } -async function PositionMigratorWrapper() { - const [vaultSummaries, marketSummaries] = await Promise.all([getVaultSummaries(), getMarketSummaries()]); +// async function PositionMigratorWrapper() { +// const [vaultSummaries, marketSummaries] = await Promise.all([getVaultSummaries(), getMarketSummaries()]); - if (!vaultSummaries || !marketSummaries) { - return null; - } - return ; -} +// if (!vaultSummaries || !marketSummaries) { +// return null; +// } +// return ; +// } export const dynamic = "force-static"; export const revalidate = 300; // 5 min diff --git a/src/components/Header/Nav.tsx b/src/components/Header/Nav.tsx index 70fc220..3794914 100644 --- a/src/components/Header/Nav.tsx +++ b/src/components/Header/Nav.tsx @@ -4,14 +4,13 @@ import { usePathname } from "next/navigation"; import { ReactNode } from "react"; import { Button } from "../ui/button"; -import ArrowFatLineDown from "../ui/icons/ArrowFatLineDown"; import BarChart from "../ui/icons/BarChart"; import CirclePlus from "../ui/icons/CirclePlus"; const NAV_ITEMS: { href: string; name: string; icon?: ReactNode; isNew?: boolean }[] = [ { href: "/", name: "Earn", icon: }, { href: "/borrow", name: "Borrow", icon: }, - { href: "/migrate", name: "Migrate", icon: }, + // { href: "/migrate", name: "Migrate", icon: }, ]; export default function Nav() { diff --git a/src/components/MarketActions/Borrow/MarketLeverageBorrow.tsx b/src/components/MarketActions/Borrow/MarketLeverageBorrow.tsx index c314c1d..b319d99 100644 --- a/src/components/MarketActions/Borrow/MarketLeverageBorrow.tsx +++ b/src/components/MarketActions/Borrow/MarketLeverageBorrow.tsx @@ -5,7 +5,7 @@ import { useConnectModal } from "@rainbow-me/rainbowkit"; import { ArrowRight, Info } from "lucide-react"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useForm } from "react-hook-form"; -import { getAddress, maxUint256, parseUnits } from "viem"; +import { getAddress, parseUnits } from "viem"; import { useAccount } from "wagmi"; import { usePublicClient } from "wagmi"; import { z } from "zod"; @@ -79,7 +79,6 @@ export default function MarketLeverageBorrow({ const rawVal = parseUnits(val, market.collateralAsset.decimals); return rawVal <= BigInt(rawCollateralTokenBalance.balance); }, "Amount exceeds wallet balance."), - isMaxCollateral: z.boolean(), multiplier: z.coerce.number().min(MIN_MULTIPLIER), maxSlippageTolerance: z.coerce.number().min(0.2).max(MAX_SLIPPAGE_TOLERANCE_PCT), }) @@ -103,19 +102,13 @@ export default function MarketLeverageBorrow({ resolver: zodResolver(formSchema), defaultValues: { initialCollateralAmount: "", - isMaxCollateral: false, multiplier: 2, maxSlippageTolerance: 0.5, }, }); const onSubmit = useCallback( - async ({ - initialCollateralAmount, - isMaxCollateral, - multiplier, - maxSlippageTolerance, - }: z.infer) => { + async ({ initialCollateralAmount, multiplier, maxSlippageTolerance }: z.infer) => { if (!address) { openConnectModal?.(); return; @@ -128,10 +121,7 @@ export default function MarketLeverageBorrow({ setSimulatingBundle(true); - const rawInitialCollateralAmount = isMaxCollateral - ? maxUint256 - : parseUnits(initialCollateralAmount, market.collateralAsset.decimals); - + const rawInitialCollateralAmount = parseUnits(initialCollateralAmount, market.collateralAsset.decimals); const leverageFactor = multiplier / (1 + maxSlippageTolerance / 100) + 1; const action = await marketLeveragedBorrowAction({ @@ -194,9 +184,6 @@ export default function MarketLeverageBorrow({ actionName="Add" asset={market.collateralAsset} rawAvailableBalance={rawCollateralTokenBalance ? BigInt(rawCollateralTokenBalance.balance) : undefined} - setIsMax={(isMax) => { - form.setValue("isMaxCollateral", isMax); - }} />
diff --git a/src/components/VaultActions/VaultSupply.tsx b/src/components/VaultActions/VaultSupply.tsx index 42f7032..1321515 100644 --- a/src/components/VaultActions/VaultSupply.tsx +++ b/src/components/VaultActions/VaultSupply.tsx @@ -4,7 +4,7 @@ import { useConnectModal } from "@rainbow-me/rainbowkit"; import { Info } from "lucide-react"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useForm } from "react-hook-form"; -import { getAddress, isAddressEqual, maxUint256, parseUnits } from "viem"; +import { getAddress, isAddressEqual, parseUnits } from "viem"; import { useAccount, useBalance, usePublicClient } from "wagmi"; import { z } from "zod"; @@ -74,7 +74,6 @@ export default function VaultSupply({ .nonempty("Amount is required.") .refine((val) => !isNaN(parseFloat(val)), "Amount must be a valid number.") .refine((val) => parseUnits(val, vault.asset.decimals) > 0n, "Amount must be greater than zero."), // This also catches the case where val is lower than token precision, but we prevent this in ActionFlowSummaryAssetItem - isMaxSupply: z.boolean(), allowWrappingNativeAssets: z.boolean(), }) .superRefine((data, ctx) => { @@ -96,7 +95,6 @@ export default function VaultSupply({ resolver: zodResolver(formSchema), defaultValues: { supplyAmount: "", - isMaxSupply: false, allowWrappingNativeAssets: isWrappedNative, }, }); @@ -115,9 +113,8 @@ export default function VaultSupply({ setSimulatingBundle(true); - // Uint256 max if the user wants to supply their entire balance - const { supplyAmount, isMaxSupply, allowWrappingNativeAssets } = values; - const rawSupplyAmount = isMaxSupply ? maxUint256 : parseUnits(supplyAmount, vault.asset.decimals); + const { supplyAmount, allowWrappingNativeAssets } = values; + const rawSupplyAmount = parseUnits(supplyAmount, vault.asset.decimals); const preparedAction = await vaultSupplyBundle({ publicClient, @@ -192,9 +189,6 @@ export default function VaultSupply({ actionName="Supply" asset={vault.asset} rawAvailableBalance={computeRawAvailableBalance(allowWrappingNativeAssets)} - setIsMax={(isMax) => { - form.setValue("isMaxSupply", isMax); - }} /> {isWrappedNative && (
diff --git a/test/config.ts b/test/config.ts index d8e9c1e..35f3043 100644 --- a/test/config.ts +++ b/test/config.ts @@ -7,7 +7,6 @@ export const test = createViemTest(polygon, { forkUrl: process.env.NEXT_PUBLIC_RPC_URL_1!, forkBlockNumber: 71095170, // forkBlockNumber: 71054290, - // hardfork: "Latest", }); export const polygonClient = createPublicClient({ @@ -19,7 +18,6 @@ export const currentBlock = await polygonClient.getBlock(); export const currentBlockTest = createViemTest(polygon, { forkUrl: process.env.NEXT_PUBLIC_RPC_URL_1!, forkBlockNumber: currentBlock.number, - hardfork: "Latest", }); // Used for tests that need a specific block number besides default from test (ex when have quotes) diff --git a/test/helpers/morpho.ts b/test/helpers/morpho.ts index 0c0e0c4..1272403 100644 --- a/test/helpers/morpho.ts +++ b/test/helpers/morpho.ts @@ -43,7 +43,24 @@ export async function getMorphoVaultPosition( const userShareBalance = await getErc20BalanceOf(client, vaultAddress, accountAddress); const userAssetBalance = vault.toAssets(userShareBalance); - return userAssetBalance; + return { userAssetBalance, userShareBalance }; +} + +export async function getMorphoVaultSharesToAssets( + client: AnvilTestClient, + vaultAddress: Address, + accountAddress: Address, + shares: bigint +) { + const simulationState = await getSimulationState({ + publicClient: client, + actionType: "vault", + accountAddress, + vaultAddress, + }); + + const vault = simulationState.getVault(vaultAddress); + return vault.toAssets(shares); } // Supply loan assets directly to a market from account for onBehalf diff --git a/test/unit/actions/market/marketLeveragedBorrowAction.test.ts b/test/unit/actions/market/marketLeveragedBorrowAction.test.ts index 4405f46..0ed4bc6 100644 --- a/test/unit/actions/market/marketLeveragedBorrowAction.test.ts +++ b/test/unit/actions/market/marketLeveragedBorrowAction.test.ts @@ -1,14 +1,18 @@ import { MarketId, MathLib } from "@morpho-org/blue-sdk"; import { fetchMarket } from "@morpho-org/blue-sdk-viem"; import { AnvilTestClient } from "@morpho-org/test"; -import { Address, maxUint256, parseEther } from "viem"; +import { Address, erc20Abi, maxUint256, parseEther } from "viem"; import { describe, expect, vi } from "vitest"; import { marketLeveragedBorrowAction } from "@/actions/market/marketLeverageBorrowAction"; -import { BUNDLER3_ADDRESS, SUPPORTED_ADDAPTERS } from "@/utils/constants"; +import { BUNDLER3_ADDRESS, GENERAL_ADAPTER_1_ADDRESS, SUPPORTED_ADDAPTERS } from "@/utils/constants"; import { test } from "../../../config"; -import { WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, WETH_USDC_MARKET_ID } from "../../../helpers/constants"; +import { + WETH_ADDRESS, + WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, + WETH_USDC_MARKET_ID, +} from "../../../helpers/constants"; import { expectZeroErc20Balances, getErc20BalanceOf } from "../../../helpers/erc20"; import { executeAction } from "../../../helpers/executeAction"; import { expectOnlyAllowedApprovals } from "../../../helpers/logs"; @@ -26,6 +30,8 @@ interface MarketLeveragedBorrowTestParameters { leverageFactor: number; maxSlippageTolerance: number; + beforeExecutionCb?: (client: AnvilTestClient) => Promise; + collateralDealAmount: bigint; callerType?: "eoa" | "contract"; } @@ -111,14 +117,60 @@ const successTestCases: ({ name: string } & Omit { + await client.deal({ erc20: WETH_ADDRESS, amount: parseEther("10") }); + + // Approval should get overwritten + await client.writeContract({ + abi: erc20Abi, + address: WETH_ADDRESS, + functionName: "approve", + args: [GENERAL_ADAPTER_1_ADDRESS, maxUint256], + }); + }, + + collateralDealAmount: parseEther("2"), + }, + { + name: "leverage with exact wallet balance collateral and increase in approval + balance before execution", marketId: WETH_USDC_MARKET_ID, allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, - initialCollateralAmount: maxUint256, + initialCollateralAmount: parseEther("2"), leverageFactor: 4.1, maxSlippageTolerance: 0.05, + beforeExecutionCb: async (client) => { + await client.deal({ erc20: WETH_ADDRESS, amount: parseEther("10") }); + + // Approval should get overwritten + await client.writeContract({ + abi: erc20Abi, + address: WETH_ADDRESS, + functionName: "approve", + args: [GENERAL_ADAPTER_1_ADDRESS, maxUint256], + }); + }, + collateralDealAmount: parseEther("2"), }, ]; @@ -189,5 +241,22 @@ describe("marketLeveragedBorrowAction", () => { }); expect(action.status).toEqual("error"); }); + test("prepare error when initial collateral amount is maxUint256", async ({ client }) => { + const action = await marketLeveragedBorrowAction({ + publicClient: client, + marketId: WETH_USDC_MARKET_ID, + allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, + + accountAddress: client.account.address, + + initialCollateralAmount: maxUint256, + leverageFactor: 20, + maxSlippageTolerance: 0.05, + }); + expect(action.status).toEqual("error"); + if (action.status === "error") { + expect(action.message).toBe("Initial collateral amount cannot be greater than or equal to max uint256"); + } + }); }); }); diff --git a/test/unit/actions/migration/aaveV3MarketMigrationAction.test.ts b/test/unit/actions/migration/aaveV3MarketMigrationAction.test.ts index 591f25c..bbc0beb 100644 --- a/test/unit/actions/migration/aaveV3MarketMigrationAction.test.ts +++ b/test/unit/actions/migration/aaveV3MarketMigrationAction.test.ts @@ -1,324 +1,336 @@ -import { AnvilTestClient } from "@morpho-org/test"; -import { Address, maxUint256, parseEther, parseUnits } from "viem"; -import { describe, expect } from "vitest"; - -import { aaveV3MarketMigrationAction } from "@/actions/migration/aaveV3MarketMigrationAction"; -import { BUNDLER3_ADDRESS, SUPPORTED_ADDAPTERS } from "@/utils/constants"; - -import { test } from "../../../config"; -import { - borrowFromAaveV3, - dealAndSupplyToAaveV3, - getAaveV3LoanBalance, - getAaveV3SupplyBalance, -} from "../../../helpers/aaveV3"; -import { USDC_ADDRESS, USDT_ADDRESS, WETH_ADDRESS, WETH_USDC_MARKET_ID } from "../../../helpers/constants"; -import { expectZeroErc20Balances } from "../../../helpers/erc20"; -import { executeAction } from "../../../helpers/executeAction"; -import { getMorphoMarketPosition } from "../../../helpers/morpho"; - -const ALLOCATING_VAULT_ADDRESS: Address[] = ["0x781FB7F6d845E3bE129289833b04d43Aa8558c42"]; - -const REBASEING_MARGIN = BigInt(100030); -const REBASEING_MARGIN_SCALE = BigInt(100000); - -async function fullPositionMigrationWithDelay( - client: AnvilTestClient, - delayBlocks: number, - collateralTokenAmount?: bigint, - loanTokenAmount?: bigint -) { - const WETH_COLLATERAL_AMOUNT = collateralTokenAmount ?? parseEther("1"); - const USDC_LOAN_AMOUNT = loanTokenAmount ?? parseUnits("100", 6); - - // Arrange - await dealAndSupplyToAaveV3(client, WETH_ADDRESS, WETH_COLLATERAL_AMOUNT, true); - await borrowFromAaveV3(client, USDC_ADDRESS, USDC_LOAN_AMOUNT); - const aaveCollateralBalanceInital = await getAaveV3SupplyBalance(client, WETH_ADDRESS); - const aaveLoanBalanceInital = await getAaveV3LoanBalance(client, USDC_ADDRESS); - - // Act - const action = await aaveV3MarketMigrationAction({ - publicClient: client, - accountAddress: client.account.address, - marketId: WETH_USDC_MARKET_ID, - collateralTokenAmount: maxUint256, - loanTokenAmount: maxUint256, - allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, - }); - - // Fast forward some time as this should still work with a time delay for execution (<1 day after creation) - await client.mine({ blocks: delayBlocks }); - await executeAction(client, action); - - // Assert - // Check aave v3 balances - const aaveV3CollateralBalanceFinal = await getAaveV3SupplyBalance(client, WETH_ADDRESS); - const aaveV3LoanBalanceFinal = await getAaveV3LoanBalance(client, USDC_ADDRESS); - expect(aaveV3CollateralBalanceFinal).toEqual(BigInt(0)); - expect(aaveV3LoanBalanceFinal).toEqual(BigInt(0)); - - // Check Morpho balances - const { collateralBalance: morphoCollateralBalanceFinal, loanBalance: morphoLoanBalanceFinal } = - await getMorphoMarketPosition(client, WETH_USDC_MARKET_ID); - - const minCollateralBalance = aaveCollateralBalanceInital; - const maxCollateralBalance = (minCollateralBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; - expect(morphoCollateralBalanceFinal).toBeWithinRange(minCollateralBalance - 1n, maxCollateralBalance); - - // The loan amount for full debt repayments always has the full buffer, +1 since rounded up - const minLoanBalance = aaveLoanBalanceInital; - const maxLoanBalance = (minLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; - expect(morphoLoanBalanceFinal).toBeWithinRange(minLoanBalance, maxLoanBalance); - - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], WETH_ADDRESS); - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], USDC_ADDRESS); -} +// import { Address, maxUint256, parseEther, parseUnits } from "viem"; +// import { describe, expect } from "vitest"; + +import { describe, test } from "vitest"; + +// import { aaveV3MarketMigrationAction } from "@/actions/migration/aaveV3MarketMigrationAction"; +// import { BUNDLER3_ADDRESS, SUPPORTED_ADDAPTERS } from "@/utils/constants"; + +// import { test } from "../../../config"; +// import { +// borrowFromAaveV3, +// dealAndSupplyToAaveV3, +// getAaveV3LoanBalance, +// getAaveV3SupplyBalance, +// } from "../../../helpers/aaveV3"; +// import { USDC_ADDRESS, WETH_ADDRESS, WETH_USDC_MARKET_ID } from "../../../helpers/constants"; +// import { expectZeroErc20Balances } from "../../../helpers/erc20"; +// import { executeAction } from "../../../helpers/executeAction"; +// import { getMorphoMarketPosition } from "../../../helpers/morpho"; + +// const ALLOCATING_VAULT_ADDRESS: Address[] = ["0x781FB7F6d845E3bE129289833b04d43Aa8558c42"]; + +// const REBASEING_MARGIN = BigInt(100030); +// const REBASEING_MARGIN_SCALE = BigInt(100000); + +// // async function fullPositionMigrationWithDelay( +// // client: AnvilTestClient, +// // delayBlocks: number, +// // collateralTokenAmount?: bigint, +// // loanTokenAmount?: bigint +// // ) { +// // const WETH_COLLATERAL_AMOUNT = collateralTokenAmount ?? parseEther("1"); +// // const USDC_LOAN_AMOUNT = loanTokenAmount ?? parseUnits("100", 6); + +// // // Arrange +// // await dealAndSupplyToAaveV3(client, WETH_ADDRESS, WETH_COLLATERAL_AMOUNT, true); +// // await borrowFromAaveV3(client, USDC_ADDRESS, USDC_LOAN_AMOUNT); +// // const aaveCollateralBalanceInital = await getAaveV3SupplyBalance(client, WETH_ADDRESS); +// // const aaveLoanBalanceInital = await getAaveV3LoanBalance(client, USDC_ADDRESS); + +// // // Act +// // const action = await aaveV3MarketMigrationAction({ +// // publicClient: client, +// // accountAddress: client.account.address, +// // marketId: WETH_USDC_MARKET_ID, +// // collateralTokenAmount: maxUint256, +// // loanTokenAmount: maxUint256, +// // allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, +// // }); + +// // // Fast forward some time as this should still work with a time delay for execution (<1 day after creation) +// // await client.mine({ blocks: delayBlocks }); +// // await executeAction(client, action); + +// // // Assert +// // // Check aave v3 balances +// // const aaveV3CollateralBalanceFinal = await getAaveV3SupplyBalance(client, WETH_ADDRESS); +// // const aaveV3LoanBalanceFinal = await getAaveV3LoanBalance(client, USDC_ADDRESS); +// // expect(aaveV3CollateralBalanceFinal).toEqual(BigInt(0)); +// // expect(aaveV3LoanBalanceFinal).toEqual(BigInt(0)); + +// // // Check Morpho balances +// // const { collateralBalance: morphoCollateralBalanceFinal, loanBalance: morphoLoanBalanceFinal } = +// // await getMorphoMarketPosition(client, WETH_USDC_MARKET_ID); + +// // const minCollateralBalance = aaveCollateralBalanceInital; +// // const maxCollateralBalance = (minCollateralBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; +// // expect(morphoCollateralBalanceFinal).toBeWithinRange(minCollateralBalance - 1n, maxCollateralBalance); + +// // // The loan amount for full debt repayments always has the full buffer, +1 since rounded up +// // const minLoanBalance = aaveLoanBalanceInital; +// // const maxLoanBalance = (minLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; +// // expect(morphoLoanBalanceFinal).toBeWithinRange(minLoanBalance, maxLoanBalance); + +// // await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], WETH_ADDRESS); +// // await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], USDC_ADDRESS); +// // } + +// describe("aaveV3MarketMigrationAction", () => { +// // Disabled for now while migration features is turned off. Fails due to check against no maxUint256 input transfer +// // describe("full position migration", () => { +// // test("should migrate full position with no delay between creation and execution", async ({ client }) => { +// // await fullPositionMigrationWithDelay(client, 0); +// // }); +// // test("should migrate full position with <1 day delay between creation and execution", async ({ client }) => { +// // await fullPositionMigrationWithDelay(client, 10000); +// // }); +// // test("should fail when migrating full position with >1 day delay between creation and execution", async ({ +// // client, +// // }) => { +// // await expect(fullPositionMigrationWithDelay(client, 500000)).rejects.toThrow("action-tx-reverted"); +// // }); +// // test("should migrate full position with public reallocation", async ({ client }) => { +// // await fullPositionMigrationWithDelay(client, 0, parseEther("10000"), parseUnits("110000", 6)); +// // }); +// // }); + +// describe("partial position migration", () => { +// // Disabled for now while migration features is turned off. Fails due to check against no maxUint256 input transfer +// // test("should migrate full collataeral, partial loan position", async ({ client }) => { +// // const wethCollateralAmount = parseEther("1"); +// // const usdtCollateralAmount = parseUnits("5000", 6); +// // const usdcLoanAmount = parseUnits("100", 6); +// // const usdcLoanMigrationAmount = usdcLoanAmount / BigInt(2); + +// // // Arrange +// // await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); +// // await dealAndSupplyToAaveV3(client, USDT_ADDRESS, usdtCollateralAmount, true); +// // await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); +// // const aaveLoanBalanceInital = await getAaveV3LoanBalance(client, USDC_ADDRESS); + +// // // Act +// // const action = await aaveV3MarketMigrationAction({ +// // publicClient: client, +// // accountAddress: client.account.address, +// // marketId: WETH_USDC_MARKET_ID, +// // collateralTokenAmount: maxUint256, +// // loanTokenAmount: usdcLoanMigrationAmount, +// // allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, +// // }); +// // await executeAction(client, action); + +// // // Assert +// // // Check aave v3 balances +// // const aaveV3CollateralBalanceFinal = await getAaveV3SupplyBalance(client, WETH_ADDRESS); +// // const aaveV3LoanBalanceFinal = await getAaveV3LoanBalance(client, USDC_ADDRESS); + +// // expect(aaveV3CollateralBalanceFinal).toEqual(BigInt(0)); + +// // const minLoanBalance = aaveLoanBalanceInital - usdcLoanMigrationAmount; +// // const maxLoanBalance = (minLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; +// // expect(aaveV3LoanBalanceFinal).toBeWithinRange(minLoanBalance - 1n, maxLoanBalance); + +// // // Check morpho balances +// // const { collateralBalance: morphoCollateralBalanceFinal, loanBalance: morphoLoanBalanceFinal } = +// // await getMorphoMarketPosition(client, WETH_USDC_MARKET_ID); + +// // expect(morphoCollateralBalanceFinal).toBeGreaterThanOrEqual(wethCollateralAmount); + +// // const minMorphoLoanBalance = usdcLoanMigrationAmount; +// // const maxMorphoLoanBalance = (minMorphoLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; +// // expect(morphoLoanBalanceFinal).toBeWithinRange(minMorphoLoanBalance, maxMorphoLoanBalance); + +// // // Make sure bundler3 and adapters have been swept +// // await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], WETH_ADDRESS); +// // await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], USDC_ADDRESS); +// // }); + +// // Disabled for now while migration features is turned off. Fails due to check against no maxUint256 input transfer +// // test("should migrate partial collataeral, full loan position", async ({ client }) => { +// // const wethCollateralAmount = parseEther("1"); +// // const usdcLoanAmount = parseUnits("100", 6); +// // const collateralMigrationAmount = wethCollateralAmount / BigInt(2); + +// // // Arrange +// // await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); +// // await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); +// // const aaveCollateralBalanceInital = await getAaveV3SupplyBalance(client, WETH_ADDRESS); + +// // // Act +// // const action = await aaveV3MarketMigrationAction({ +// // publicClient: client, +// // accountAddress: client.account.address, +// // marketId: WETH_USDC_MARKET_ID, +// // collateralTokenAmount: collateralMigrationAmount, +// // loanTokenAmount: maxUint256, +// // allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, +// // }); +// // await executeAction(client, action); + +// // // Assert +// // // Check aave v3 balances +// // const aaveV3CollateralBalanceFinal = await getAaveV3SupplyBalance(client, WETH_ADDRESS); +// // const aaveV3LoanBalanceFinal = await getAaveV3LoanBalance(client, USDC_ADDRESS); + +// // const minCollateralBalance = aaveCollateralBalanceInital - collateralMigrationAmount; +// // const maxCollateralBalance = (minCollateralBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; +// // expect(aaveV3CollateralBalanceFinal).toBeWithinRange(minCollateralBalance, maxCollateralBalance); + +// // expect(aaveV3LoanBalanceFinal).toEqual(BigInt(0)); + +// // // Check morpho balances +// // const { collateralBalance: morphoCollateralBalanceFinal, loanBalance: morphoLoanBalanceFinal } = +// // await getMorphoMarketPosition(client, WETH_USDC_MARKET_ID); + +// // expect(morphoCollateralBalanceFinal).toBeGreaterThanOrEqual(collateralMigrationAmount); + +// // // The loan amount for full debt repayments always has the full buffer, +1 since rounded up +// // const minLoanBalance = usdcLoanAmount; +// // const maxLoanBalance = (minLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; +// // expect(morphoLoanBalanceFinal).toBeWithinRange(minLoanBalance, maxLoanBalance); + +// // // Make sure bundler3 and adapters have been swept +// // await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], WETH_ADDRESS); +// // await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], USDC_ADDRESS); +// // }); + +// test("should migrate partial collateral, partial loan position", async ({ client }) => { +// const wethCollateralAmount = parseEther("1"); +// const usdcLoanAmount = parseUnits("100", 6); +// const collateralMigrationAmount = wethCollateralAmount / BigInt(2); +// const loanMigrationAmount = usdcLoanAmount / BigInt(2); + +// // Arrange +// await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); +// await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); +// const aaveCollateralBalanceInital = await getAaveV3SupplyBalance(client, WETH_ADDRESS); +// const aaveLoanBalanceInital = await getAaveV3LoanBalance(client, USDC_ADDRESS); + +// // Act +// const action = await aaveV3MarketMigrationAction({ +// publicClient: client, +// accountAddress: client.account.address, +// marketId: WETH_USDC_MARKET_ID, +// collateralTokenAmount: collateralMigrationAmount, +// loanTokenAmount: loanMigrationAmount, +// allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, +// }); +// await executeAction(client, action); + +// // Assert +// // Check aave v3 balances +// const aaveV3CollateralBalanceFinal = await getAaveV3SupplyBalance(client, WETH_ADDRESS); +// const aaveV3LoanBalanceFinal = await getAaveV3LoanBalance(client, USDC_ADDRESS); + +// const minCollateralBalance = aaveCollateralBalanceInital - collateralMigrationAmount - 1n; +// const maxCollateralBalance = (minCollateralBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; +// expect(aaveV3CollateralBalanceFinal).toBeWithinRange(minCollateralBalance, maxCollateralBalance); + +// const minLoanBalance = aaveLoanBalanceInital - loanMigrationAmount - 1n; +// const maxLoanBalance = (minLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; +// expect(aaveV3LoanBalanceFinal).toBeWithinRange(minLoanBalance, maxLoanBalance); + +// // Check morpho balances +// const { collateralBalance: morphoCollateralBalanceFinal, loanBalance: morphoLoanBalanceFinal } = +// await getMorphoMarketPosition(client, WETH_USDC_MARKET_ID); + +// expect(morphoCollateralBalanceFinal).toEqual(collateralMigrationAmount); +// expect(morphoLoanBalanceFinal).toEqual(loanMigrationAmount + BigInt(1)); + +// // Make sure bundler3 and adapters have been swept +// await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], WETH_ADDRESS); +// await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], USDC_ADDRESS); +// }); +// }); + +// describe("unhealthy position migration", () => { +// test("should fail to migrate if leaving unhealthy aave position", async ({ client }) => { +// const wethCollateralAmount = parseEther("1"); +// const usdcLoanAmount = parseUnits("100", 6); + +// // Arrange +// await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); +// await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); + +// // Act +// const action = await aaveV3MarketMigrationAction({ +// publicClient: client, +// accountAddress: client.account.address, +// marketId: WETH_USDC_MARKET_ID, +// collateralTokenAmount: wethCollateralAmount, +// loanTokenAmount: BigInt(1), +// allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, +// }); +// await expect(executeAction(client, action)).rejects.toThrow("action-tx-reverted"); +// }); +// test("should fail to migrate if creating unhealthy morpho position", async ({ client }) => { +// const wethCollateralAmount = parseEther("1"); +// const usdcLoanAmount = parseUnits("100", 6); + +// // Arrange +// await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); +// await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); + +// // Act +// const action = await aaveV3MarketMigrationAction({ +// publicClient: client, +// accountAddress: client.account.address, +// marketId: WETH_USDC_MARKET_ID, +// collateralTokenAmount: BigInt(1), +// loanTokenAmount: maxUint256, +// allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, +// }); +// // Will fail in simulation since we fully simulate Morpho side +// expect(action.status).toBe("error"); +// }); +// }); + +// describe("input validation", () => { +// test("should fail to migrate if loan token amount is 0", async ({ client }) => { +// const wethCollateralAmount = parseEther("1"); +// const usdcLoanAmount = parseUnits("100", 6); +// const collateralMigrationAmount = wethCollateralAmount / BigInt(2); + +// // Arrange +// await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); +// await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); + +// // Act +// const action = await aaveV3MarketMigrationAction({ +// publicClient: client, +// accountAddress: client.account.address, +// marketId: WETH_USDC_MARKET_ID, +// collateralTokenAmount: collateralMigrationAmount, +// loanTokenAmount: BigInt(0), +// allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, +// }); +// expect(action.status).toBe("error"); +// }); +// test("should fail to migrate if collateral token amount is 0", async ({ client }) => { +// const wethCollateralAmount = parseEther("1"); +// const usdcLoanAmount = parseUnits("100", 6); + +// // Arrange +// await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); +// await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); + +// // Act +// const action = await aaveV3MarketMigrationAction({ +// publicClient: client, +// accountAddress: client.account.address, +// marketId: WETH_USDC_MARKET_ID, +// collateralTokenAmount: BigInt(0), +// loanTokenAmount: usdcLoanAmount, +// allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, +// }); +// expect(action.status).toBe("error"); // Would fail anyways in sim since no Morpho collateral +// }); +// }); +// }); describe("aaveV3MarketMigrationAction", () => { - describe("full position migration", () => { - test("should migrate full position with no delay between creation and execution", async ({ client }) => { - await fullPositionMigrationWithDelay(client, 0); - }); - test("should migrate full position with <1 day delay between creation and execution", async ({ client }) => { - await fullPositionMigrationWithDelay(client, 10000); - }); - test("should fail when migrating full position with >1 day delay between creation and execution", async ({ - client, - }) => { - await expect(fullPositionMigrationWithDelay(client, 500000)).rejects.toThrow("action-tx-reverted"); - }); - test("should migrate full position with public reallocation", async ({ client }) => { - await fullPositionMigrationWithDelay(client, 0, parseEther("10000"), parseUnits("110000", 6)); - }); - }); - - describe("partial position migration", () => { - test("should migrate full collataeral, partial loan position", async ({ client }) => { - const wethCollateralAmount = parseEther("1"); - const usdtCollateralAmount = parseUnits("5000", 6); - const usdcLoanAmount = parseUnits("100", 6); - const usdcLoanMigrationAmount = usdcLoanAmount / BigInt(2); - - // Arrange - await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); - await dealAndSupplyToAaveV3(client, USDT_ADDRESS, usdtCollateralAmount, true); - await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); - const aaveLoanBalanceInital = await getAaveV3LoanBalance(client, USDC_ADDRESS); - - // Act - const action = await aaveV3MarketMigrationAction({ - publicClient: client, - accountAddress: client.account.address, - marketId: WETH_USDC_MARKET_ID, - collateralTokenAmount: maxUint256, - loanTokenAmount: usdcLoanMigrationAmount, - allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, - }); - await executeAction(client, action); - - // Assert - // Check aave v3 balances - const aaveV3CollateralBalanceFinal = await getAaveV3SupplyBalance(client, WETH_ADDRESS); - const aaveV3LoanBalanceFinal = await getAaveV3LoanBalance(client, USDC_ADDRESS); - - expect(aaveV3CollateralBalanceFinal).toEqual(BigInt(0)); - - const minLoanBalance = aaveLoanBalanceInital - usdcLoanMigrationAmount; - const maxLoanBalance = (minLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; - expect(aaveV3LoanBalanceFinal).toBeWithinRange(minLoanBalance - 1n, maxLoanBalance); - - // Check morpho balances - const { collateralBalance: morphoCollateralBalanceFinal, loanBalance: morphoLoanBalanceFinal } = - await getMorphoMarketPosition(client, WETH_USDC_MARKET_ID); - - expect(morphoCollateralBalanceFinal).toBeGreaterThanOrEqual(wethCollateralAmount); - - const minMorphoLoanBalance = usdcLoanMigrationAmount; - const maxMorphoLoanBalance = (minMorphoLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; - expect(morphoLoanBalanceFinal).toBeWithinRange(minMorphoLoanBalance, maxMorphoLoanBalance); - - // Make sure bundler3 and adapters have been swept - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], WETH_ADDRESS); - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], USDC_ADDRESS); - }); - test("should migrate partial collataeral, full loan position", async ({ client }) => { - const wethCollateralAmount = parseEther("1"); - const usdcLoanAmount = parseUnits("100", 6); - const collateralMigrationAmount = wethCollateralAmount / BigInt(2); - - // Arrange - await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); - await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); - const aaveCollateralBalanceInital = await getAaveV3SupplyBalance(client, WETH_ADDRESS); - - // Act - const action = await aaveV3MarketMigrationAction({ - publicClient: client, - accountAddress: client.account.address, - marketId: WETH_USDC_MARKET_ID, - collateralTokenAmount: collateralMigrationAmount, - loanTokenAmount: maxUint256, - allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, - }); - await executeAction(client, action); - - // Assert - // Check aave v3 balances - const aaveV3CollateralBalanceFinal = await getAaveV3SupplyBalance(client, WETH_ADDRESS); - const aaveV3LoanBalanceFinal = await getAaveV3LoanBalance(client, USDC_ADDRESS); - - const minCollateralBalance = aaveCollateralBalanceInital - collateralMigrationAmount; - const maxCollateralBalance = (minCollateralBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; - expect(aaveV3CollateralBalanceFinal).toBeWithinRange(minCollateralBalance, maxCollateralBalance); - - expect(aaveV3LoanBalanceFinal).toEqual(BigInt(0)); - - // Check morpho balances - const { collateralBalance: morphoCollateralBalanceFinal, loanBalance: morphoLoanBalanceFinal } = - await getMorphoMarketPosition(client, WETH_USDC_MARKET_ID); - - expect(morphoCollateralBalanceFinal).toBeGreaterThanOrEqual(collateralMigrationAmount); - - // The loan amount for full debt repayments always has the full buffer, +1 since rounded up - const minLoanBalance = usdcLoanAmount; - const maxLoanBalance = (minLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; - expect(morphoLoanBalanceFinal).toBeWithinRange(minLoanBalance, maxLoanBalance); - - // Make sure bundler3 and adapters have been swept - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], WETH_ADDRESS); - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], USDC_ADDRESS); - }); - test("should migrate partial collateral, partial loan position", async ({ client }) => { - const wethCollateralAmount = parseEther("1"); - const usdcLoanAmount = parseUnits("100", 6); - const collateralMigrationAmount = wethCollateralAmount / BigInt(2); - const loanMigrationAmount = usdcLoanAmount / BigInt(2); - - // Arrange - await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); - await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); - const aaveCollateralBalanceInital = await getAaveV3SupplyBalance(client, WETH_ADDRESS); - const aaveLoanBalanceInital = await getAaveV3LoanBalance(client, USDC_ADDRESS); - - // Act - const action = await aaveV3MarketMigrationAction({ - publicClient: client, - accountAddress: client.account.address, - marketId: WETH_USDC_MARKET_ID, - collateralTokenAmount: collateralMigrationAmount, - loanTokenAmount: loanMigrationAmount, - allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, - }); - await executeAction(client, action); - - // Assert - // Check aave v3 balances - const aaveV3CollateralBalanceFinal = await getAaveV3SupplyBalance(client, WETH_ADDRESS); - const aaveV3LoanBalanceFinal = await getAaveV3LoanBalance(client, USDC_ADDRESS); - - const minCollateralBalance = aaveCollateralBalanceInital - collateralMigrationAmount - 1n; - const maxCollateralBalance = (minCollateralBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; - expect(aaveV3CollateralBalanceFinal).toBeWithinRange(minCollateralBalance, maxCollateralBalance); - - const minLoanBalance = aaveLoanBalanceInital - loanMigrationAmount - 1n; - const maxLoanBalance = (minLoanBalance * REBASEING_MARGIN) / REBASEING_MARGIN_SCALE; - expect(aaveV3LoanBalanceFinal).toBeWithinRange(minLoanBalance, maxLoanBalance); - - // Check morpho balances - const { collateralBalance: morphoCollateralBalanceFinal, loanBalance: morphoLoanBalanceFinal } = - await getMorphoMarketPosition(client, WETH_USDC_MARKET_ID); - - expect(morphoCollateralBalanceFinal).toEqual(collateralMigrationAmount); - expect(morphoLoanBalanceFinal).toEqual(loanMigrationAmount + BigInt(1)); - - // Make sure bundler3 and adapters have been swept - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], WETH_ADDRESS); - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], USDC_ADDRESS); - }); - }); - - describe("unhealthy position migration", () => { - test("should fail to migrate if leaving unhealthy aave position", async ({ client }) => { - const wethCollateralAmount = parseEther("1"); - const usdcLoanAmount = parseUnits("100", 6); - - // Arrange - await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); - await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); - - // Act - const action = await aaveV3MarketMigrationAction({ - publicClient: client, - accountAddress: client.account.address, - marketId: WETH_USDC_MARKET_ID, - collateralTokenAmount: maxUint256, - loanTokenAmount: BigInt(1), - allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, - }); - await expect(executeAction(client, action)).rejects.toThrow("action-tx-reverted"); - }); - test("should fail to migrate if creating unhealthy morpho position", async ({ client }) => { - const wethCollateralAmount = parseEther("1"); - const usdcLoanAmount = parseUnits("100", 6); - - // Arrange - await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); - await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); - - // Act - const action = await aaveV3MarketMigrationAction({ - publicClient: client, - accountAddress: client.account.address, - marketId: WETH_USDC_MARKET_ID, - collateralTokenAmount: BigInt(1), - loanTokenAmount: maxUint256, - allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, - }); - // Will fail in simulation since we fully simulate Morpho side - expect(action.status).toBe("error"); - }); - }); - - describe("input validation", () => { - test("should fail to migrate if loan token amount is 0", async ({ client }) => { - const wethCollateralAmount = parseEther("1"); - const usdcLoanAmount = parseUnits("100", 6); - const collateralMigrationAmount = wethCollateralAmount / BigInt(2); - - // Arrange - await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); - await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); - - // Act - const action = await aaveV3MarketMigrationAction({ - publicClient: client, - accountAddress: client.account.address, - marketId: WETH_USDC_MARKET_ID, - collateralTokenAmount: collateralMigrationAmount, - loanTokenAmount: BigInt(0), - allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, - }); - expect(action.status).toBe("error"); - }); - test("should fail to migrate if collateral token amount is 0", async ({ client }) => { - const wethCollateralAmount = parseEther("1"); - const usdcLoanAmount = parseUnits("100", 6); - - // Arrange - await dealAndSupplyToAaveV3(client, WETH_ADDRESS, wethCollateralAmount, true); - await borrowFromAaveV3(client, USDC_ADDRESS, usdcLoanAmount); - - // Act - const action = await aaveV3MarketMigrationAction({ - publicClient: client, - accountAddress: client.account.address, - marketId: WETH_USDC_MARKET_ID, - collateralTokenAmount: BigInt(0), - loanTokenAmount: usdcLoanAmount, - allocatingVaultAddresses: ALLOCATING_VAULT_ADDRESS, - }); - expect(action.status).toBe("error"); // Would fail anyways in sim since no Morpho collateral - }); + test("unused", () => { + // Unused: satifies vitest }); }); diff --git a/test/unit/actions/migration/aaveV3PortfolioMigrationToMarketAction.test.ts b/test/unit/actions/migration/aaveV3PortfolioMigrationToMarketAction.test.ts index fe1778c..0db68ab 100644 --- a/test/unit/actions/migration/aaveV3PortfolioMigrationToMarketAction.test.ts +++ b/test/unit/actions/migration/aaveV3PortfolioMigrationToMarketAction.test.ts @@ -1,217 +1,225 @@ -import { MarketId } from "@morpho-org/blue-sdk"; -import { AnvilTestClient } from "@morpho-org/test"; -import { Address, parseEther, parseUnits } from "viem"; -import { describe, expect } from "vitest"; - -import { aaveV3PortfolioMigrationToMarketAction } from "@/actions/migration/aaveV3PortfolioMigrationToMarketAction"; -import { USDC_ADDRESS, WBTC_ADDRESS } from "@/config"; -import { BUNDLER3_ADDRESS, SUPPORTED_ADDAPTERS } from "@/utils/constants"; - -import { test } from "../../../config"; -import { dealAndSupplyToAaveV3 } from "../../../helpers/aaveV3"; -import { borrowFromAaveV3 } from "../../../helpers/aaveV3"; -import { - DAI_ADDRESS, - USDT_ADDRESS, - WETH_ADDRESS, - WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, - WETH_USDC_MARKET_ID, -} from "../../../helpers/constants"; -import { expectZeroErc20Balances } from "../../../helpers/erc20"; -import { executeAction } from "../../../helpers/executeAction"; -import { expectOnlyAllowedApprovals } from "../../../helpers/logs"; -import { getMorphoMarketPosition, seedMarketLiquidity } from "../../../helpers/morpho"; -import { paraswapSnapshotTest } from "../../snapshots/paraswapSnapshotTest"; - -interface RunAaveV3PortfolioMigrationToMarketActionTestParameters { - client: AnvilTestClient; - - portfolioPercentage: number; - maxSlippageTolerance: number; - - marketId: MarketId; - allocatingVaultAddresses: Address[]; - borrowAmount: bigint; - - // Must be correctly collateralized - initialPositions: { assetAddress: Address; supplyAmount: bigint; borrowAmount: bigint }[]; - - minCollateralAmount: bigint; -} - -async function runAaveV3PortfolioMigrationToMarketActionTest({ - client, - - portfolioPercentage, - maxSlippageTolerance, - - marketId, - allocatingVaultAddresses, - borrowAmount, - - initialPositions, - minCollateralAmount, -}: RunAaveV3PortfolioMigrationToMarketActionTestParameters) { - // Arrange - const collateralPositions = initialPositions.filter((p) => p.supplyAmount > 0n); - const borrowPositions = initialPositions.filter((p) => p.borrowAmount > 0n); - - for (const p of collateralPositions) { - await dealAndSupplyToAaveV3(client, p.assetAddress, p.supplyAmount, true); - } - for (const p of borrowPositions) { - await borrowFromAaveV3(client, p.assetAddress, p.borrowAmount); - } - - await seedMarketLiquidity(client, marketId, borrowAmount); - - // Act - const action = await aaveV3PortfolioMigrationToMarketAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage, - maxSlippageTolerance, - - marketId, - allocatingVaultAddresses, - borrowAmount, - }); - const logs = await executeAction(client, action); - - // Assert - await expectOnlyAllowedApprovals(client, logs, client.account.address); // Make sure doesn't approve or permit anything unexpected - - // Make sure no dust left anywhere - for (const p of initialPositions) { - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], p.assetAddress); - } - - const positionBalance = await getMorphoMarketPosition(client, marketId, client.account.address); - expect(positionBalance.collateralBalance).toBeGreaterThanOrEqual(minCollateralAmount); - expect(positionBalance.loanBalance).toBeWithinRange(borrowAmount - 1n, borrowAmount + 1n); // For rounding -} - -const initialPositions = [ - { assetAddress: USDC_ADDRESS, supplyAmount: parseUnits("1000", 6), borrowAmount: parseUnits("10", 6) }, // 1000, 10 - { assetAddress: USDT_ADDRESS, supplyAmount: parseUnits("2000", 6), borrowAmount: parseUnits("500", 6) }, // 2000, 500 - { assetAddress: WETH_ADDRESS, supplyAmount: parseEther("1"), borrowAmount: parseEther("0") }, // 2330, 0 - { assetAddress: DAI_ADDRESS, supplyAmount: parseUnits("0", 18), borrowAmount: parseUnits("2000", 18) }, // 0, 2000 - { assetAddress: WBTC_ADDRESS, supplyAmount: parseUnits("0", 8), borrowAmount: parseUnits("0.01", 8) }, // 0, 1031 -]; - -// Total supply value USD: 5330 -// Total borrow value USD: 3541 -// Total delta USD: 1789 => ~0.76 ETH +// import { MarketId } from "@morpho-org/blue-sdk"; +// import { AnvilTestClient } from "@morpho-org/test"; +// import { Address, parseEther, parseUnits } from "viem"; +// import { describe, expect } from "vitest"; + +import { describe, test } from "vitest"; + +// import { aaveV3PortfolioMigrationToMarketAction } from "@/actions/migration/aaveV3PortfolioMigrationToMarketAction"; +// import { USDC_ADDRESS, WBTC_ADDRESS } from "@/config"; +// import { BUNDLER3_ADDRESS, SUPPORTED_ADDAPTERS } from "@/utils/constants"; + +// import { test } from "../../../config"; +// import { dealAndSupplyToAaveV3 } from "../../../helpers/aaveV3"; +// import { borrowFromAaveV3 } from "../../../helpers/aaveV3"; +// import { +// DAI_ADDRESS, +// USDT_ADDRESS, +// WETH_ADDRESS, +// WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, +// WETH_USDC_MARKET_ID, +// } from "../../../helpers/constants"; +// import { expectZeroErc20Balances } from "../../../helpers/erc20"; +// import { executeAction } from "../../../helpers/executeAction"; +// import { expectOnlyAllowedApprovals } from "../../../helpers/logs"; +// import { getMorphoMarketPosition, seedMarketLiquidity } from "../../../helpers/morpho"; +// import { paraswapSnapshotTest } from "../../snapshots/paraswapSnapshotTest"; + +// interface RunAaveV3PortfolioMigrationToMarketActionTestParameters { +// client: AnvilTestClient; + +// portfolioPercentage: number; +// maxSlippageTolerance: number; + +// marketId: MarketId; +// allocatingVaultAddresses: Address[]; +// borrowAmount: bigint; + +// // Must be correctly collateralized +// initialPositions: { assetAddress: Address; supplyAmount: bigint; borrowAmount: bigint }[]; + +// minCollateralAmount: bigint; +// } + +// async function runAaveV3PortfolioMigrationToMarketActionTest({ +// client, + +// portfolioPercentage, +// maxSlippageTolerance, + +// marketId, +// allocatingVaultAddresses, +// borrowAmount, + +// initialPositions, +// minCollateralAmount, +// }: RunAaveV3PortfolioMigrationToMarketActionTestParameters) { +// // Arrange +// const collateralPositions = initialPositions.filter((p) => p.supplyAmount > 0n); +// const borrowPositions = initialPositions.filter((p) => p.borrowAmount > 0n); + +// for (const p of collateralPositions) { +// await dealAndSupplyToAaveV3(client, p.assetAddress, p.supplyAmount, true); +// } +// for (const p of borrowPositions) { +// await borrowFromAaveV3(client, p.assetAddress, p.borrowAmount); +// } + +// await seedMarketLiquidity(client, marketId, borrowAmount); + +// // Act +// const action = await aaveV3PortfolioMigrationToMarketAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage, +// maxSlippageTolerance, + +// marketId, +// allocatingVaultAddresses, +// borrowAmount, +// }); +// const logs = await executeAction(client, action); + +// // Assert +// await expectOnlyAllowedApprovals(client, logs, client.account.address); // Make sure doesn't approve or permit anything unexpected + +// // Make sure no dust left anywhere +// for (const p of initialPositions) { +// await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], p.assetAddress); +// } + +// const positionBalance = await getMorphoMarketPosition(client, marketId, client.account.address); +// expect(positionBalance.collateralBalance).toBeGreaterThanOrEqual(minCollateralAmount); +// expect(positionBalance.loanBalance).toBeWithinRange(borrowAmount - 1n, borrowAmount + 1n); // For rounding +// } + +// const initialPositions = [ +// { assetAddress: USDC_ADDRESS, supplyAmount: parseUnits("1000", 6), borrowAmount: parseUnits("10", 6) }, // 1000, 10 +// { assetAddress: USDT_ADDRESS, supplyAmount: parseUnits("2000", 6), borrowAmount: parseUnits("500", 6) }, // 2000, 500 +// { assetAddress: WETH_ADDRESS, supplyAmount: parseEther("1"), borrowAmount: parseEther("0") }, // 2330, 0 +// { assetAddress: DAI_ADDRESS, supplyAmount: parseUnits("0", 18), borrowAmount: parseUnits("2000", 18) }, // 0, 2000 +// { assetAddress: WBTC_ADDRESS, supplyAmount: parseUnits("0", 8), borrowAmount: parseUnits("0.01", 8) }, // 0, 1031 +// ]; + +// // Total supply value USD: 5330 +// // Total borrow value USD: 3541 +// // Total delta USD: 1789 => ~0.76 ETH + +// describe("aaveV3PortfolioMigrationToMarketAction", () => { +// describe("happy path", () => { +// paraswapSnapshotTest("partial migration, WETH-USDC market", async ({ client }) => { +// await runAaveV3PortfolioMigrationToMarketActionTest({ +// client, + +// portfolioPercentage: 0.5, +// maxSlippageTolerance: 0.015, +// marketId: WETH_USDC_MARKET_ID, +// allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, +// borrowAmount: parseUnits("100", 6), + +// initialPositions, +// minCollateralAmount: parseEther("0.37"), // Need to update if taking a new snapshot to reflect ETH price +// }); +// }); +// // paraswapSnapshotTest("full migration, WETH-USDC market", async ({ client }) => { +// // await runAaveV3PortfolioMigrationToMarketActionTest({ +// // client, + +// // portfolioPercentage: 1, +// // maxSlippageTolerance: 0.015, +// // marketId: WETH_USDC_MARKET_ID, +// // allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, +// // borrowAmount: parseUnits("400", 6), + +// // initialPositions, +// // minCollateralAmount: parseEther("0.74"), // Need to update if taking a new snapshot to reflect ETH price +// // }); +// // }); +// }); + +// describe("sad path", () => { +// test("portfolio percentage is 0", async ({ client }) => { +// const action = await aaveV3PortfolioMigrationToMarketAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage: 0, +// maxSlippageTolerance: 0.015, + +// marketId: WETH_USDC_MARKET_ID, +// allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, +// borrowAmount: parseUnits("100", 6), +// }); +// expect(action.status).toEqual("error"); + +// if (action.status == "error") { +// expect(action.message).toEqual( +// "Simulation Error: Portfolio percentage must be between 0 (exclusive) and 1 (inclusive)" +// ); +// } +// }); +// test("portfolio percentage is >1", async ({ client }) => { +// const action = await aaveV3PortfolioMigrationToMarketAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage: 1.1, +// maxSlippageTolerance: 0.015, + +// marketId: WETH_USDC_MARKET_ID, +// allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, +// borrowAmount: parseUnits("100", 6), +// }); +// expect(action.status).toEqual("error"); + +// if (action.status == "error") { +// expect(action.message).toEqual( +// "Simulation Error: Portfolio percentage must be between 0 (exclusive) and 1 (inclusive)" +// ); +// } +// }); +// test("slippage is 0", async ({ client }) => { +// const action = await aaveV3PortfolioMigrationToMarketAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage: 0.5, +// maxSlippageTolerance: 0, + +// marketId: WETH_USDC_MARKET_ID, +// allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, +// borrowAmount: parseUnits("100", 6), +// }); +// expect(action.status).toEqual("error"); + +// if (action.status == "error") { +// expect(action.message).toEqual("Simulation Error: Max slippage tolerance must be between 0 and 0.5"); +// } +// }); +// test("slippage is >0.5", async ({ client }) => { +// const action = await aaveV3PortfolioMigrationToMarketAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage: 0.5, +// maxSlippageTolerance: 0.51, + +// marketId: WETH_USDC_MARKET_ID, +// allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, +// borrowAmount: parseUnits("100", 6), +// }); +// expect(action.status).toEqual("error"); + +// if (action.status == "error") { +// expect(action.message).toEqual("Simulation Error: Max slippage tolerance must be between 0 and 0.5"); +// } +// }); +// }); +// }); describe("aaveV3PortfolioMigrationToMarketAction", () => { - describe("happy path", () => { - paraswapSnapshotTest("partial migration, WETH-USDC market", async ({ client }) => { - await runAaveV3PortfolioMigrationToMarketActionTest({ - client, - - portfolioPercentage: 0.5, - maxSlippageTolerance: 0.015, - marketId: WETH_USDC_MARKET_ID, - allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, - borrowAmount: parseUnits("100", 6), - - initialPositions, - minCollateralAmount: parseEther("0.37"), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - paraswapSnapshotTest("full migration, WETH-USDC market", async ({ client }) => { - await runAaveV3PortfolioMigrationToMarketActionTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - marketId: WETH_USDC_MARKET_ID, - allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, - borrowAmount: parseUnits("400", 6), - - initialPositions, - minCollateralAmount: parseEther("0.74"), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - }); - - describe("sad path", () => { - test("portfolio percentage is 0", async ({ client }) => { - const action = await aaveV3PortfolioMigrationToMarketAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage: 0, - maxSlippageTolerance: 0.015, - - marketId: WETH_USDC_MARKET_ID, - allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, - borrowAmount: parseUnits("100", 6), - }); - expect(action.status).toEqual("error"); - - if (action.status == "error") { - expect(action.message).toEqual( - "Simulation Error: Portfolio percentage must be between 0 (exclusive) and 1 (inclusive)" - ); - } - }); - test("portfolio percentage is >1", async ({ client }) => { - const action = await aaveV3PortfolioMigrationToMarketAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage: 1.1, - maxSlippageTolerance: 0.015, - - marketId: WETH_USDC_MARKET_ID, - allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, - borrowAmount: parseUnits("100", 6), - }); - expect(action.status).toEqual("error"); - - if (action.status == "error") { - expect(action.message).toEqual( - "Simulation Error: Portfolio percentage must be between 0 (exclusive) and 1 (inclusive)" - ); - } - }); - test("slippage is 0", async ({ client }) => { - const action = await aaveV3PortfolioMigrationToMarketAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage: 0.5, - maxSlippageTolerance: 0, - - marketId: WETH_USDC_MARKET_ID, - allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, - borrowAmount: parseUnits("100", 6), - }); - expect(action.status).toEqual("error"); - - if (action.status == "error") { - expect(action.message).toEqual("Simulation Error: Max slippage tolerance must be between 0 and 0.5"); - } - }); - test("slippage is >0.5", async ({ client }) => { - const action = await aaveV3PortfolioMigrationToMarketAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage: 0.5, - maxSlippageTolerance: 0.51, - - marketId: WETH_USDC_MARKET_ID, - allocatingVaultAddresses: WETH_USDC_MARKET_ALLOCATING_VAULT_ADDRESS, - borrowAmount: parseUnits("100", 6), - }); - expect(action.status).toEqual("error"); - - if (action.status == "error") { - expect(action.message).toEqual("Simulation Error: Max slippage tolerance must be between 0 and 0.5"); - } - }); + test("unused", () => { + // Unused: satifies vitest }); }); diff --git a/test/unit/actions/migration/aaveV3PortfolioMigrationToVaultAction.test.ts b/test/unit/actions/migration/aaveV3PortfolioMigrationToVaultAction.test.ts index 85c5115..48756a4 100644 --- a/test/unit/actions/migration/aaveV3PortfolioMigrationToVaultAction.test.ts +++ b/test/unit/actions/migration/aaveV3PortfolioMigrationToVaultAction.test.ts @@ -1,212 +1,220 @@ -import { AnvilTestClient } from "@morpho-org/test"; -import { Address, parseEther, parseUnits } from "viem"; -import { describe, expect } from "vitest"; - -import { aaveV3PortfolioMigrationToVaultAction } from "@/actions/migration/aaveV3PortfolioMigrationToVaultAction"; -import { USDC_ADDRESS } from "@/config"; -import { BUNDLER3_ADDRESS, SUPPORTED_ADDAPTERS } from "@/utils/constants"; - -import { test } from "../../../config"; -import { dealAndSupplyToAaveV3 } from "../../../helpers/aaveV3"; -import { borrowFromAaveV3 } from "../../../helpers/aaveV3"; -import { - DAI_ADDRESS, - USDC_VAULT_ADDRESS, - USDT_ADDRESS, - WETH_ADDRESS, - WPOL_VAULT_ADDRESS, -} from "../../../helpers/constants"; -import { expectZeroErc20Balances } from "../../../helpers/erc20"; -import { executeAction } from "../../../helpers/executeAction"; -import { expectOnlyAllowedApprovals } from "../../../helpers/logs"; -import { getMorphoVaultPosition } from "../../../helpers/morpho"; -import { paraswapSnapshotTest } from "../../snapshots/paraswapSnapshotTest"; - -interface RunAaveV3PortfolioMigrationToVaultActionTestParameters { - client: AnvilTestClient; - - portfolioPercentage: number; - maxSlippageTolerance: number; - vaultAddress: Address; - - // Must be correctly collateralized - initialPositions: { assetAddress: Address; supplyAmount: bigint; borrowAmount: bigint }[]; - - minVaultPosition: bigint; // In vault asset -} - -async function runAaveV3PortfolioMigrationToVaultActionTest({ - client, - - portfolioPercentage, - maxSlippageTolerance, - vaultAddress, - - initialPositions, - minVaultPosition, -}: RunAaveV3PortfolioMigrationToVaultActionTestParameters) { - // Arrange - const collateralPositions = initialPositions.filter((p) => p.supplyAmount > 0n); - const borrowPositions = initialPositions.filter((p) => p.borrowAmount > 0n); - - for (const p of collateralPositions) { - await dealAndSupplyToAaveV3(client, p.assetAddress, p.supplyAmount, true); - } - for (const p of borrowPositions) { - await borrowFromAaveV3(client, p.assetAddress, p.borrowAmount); - } - - // Act - const action = await aaveV3PortfolioMigrationToVaultAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage, - maxSlippageTolerance, - - vaultAddress, - }); - const logs = await executeAction(client, action); - - // Assert - await expectOnlyAllowedApprovals(client, logs, client.account.address); // Make sure doesn't approve or permit anything unexpected - - // Make sure no dust left anywhere - for (const p of initialPositions) { - await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], p.assetAddress); - } - - const positionBalance = await getMorphoVaultPosition(client, vaultAddress); - expect(positionBalance).toBeGreaterThanOrEqual(minVaultPosition); -} - -const initialPositions = [ - { assetAddress: USDC_ADDRESS, supplyAmount: parseUnits("1000", 6), borrowAmount: parseUnits("10", 6) }, - { assetAddress: USDT_ADDRESS, supplyAmount: parseUnits("2000", 6), borrowAmount: parseUnits("500", 6) }, - { assetAddress: WETH_ADDRESS, supplyAmount: parseEther("1"), borrowAmount: parseEther("0") }, - { assetAddress: DAI_ADDRESS, supplyAmount: parseUnits("0", 18), borrowAmount: parseUnits("2000", 18) }, -]; +// import { AnvilTestClient } from "@morpho-org/test"; +// import { Address, parseEther, parseUnits } from "viem"; +// import { describe, expect } from "vitest"; + +import { describe, test } from "vitest"; + +// import { aaveV3PortfolioMigrationToVaultAction } from "@/actions/migration/aaveV3PortfolioMigrationToVaultAction"; +// import { USDC_ADDRESS } from "@/config"; +// import { BUNDLER3_ADDRESS, SUPPORTED_ADDAPTERS } from "@/utils/constants"; + +// import { test } from "../../../config"; +// import { dealAndSupplyToAaveV3 } from "../../../helpers/aaveV3"; +// import { borrowFromAaveV3 } from "../../../helpers/aaveV3"; +// import { +// DAI_ADDRESS, +// USDC_VAULT_ADDRESS, +// USDT_ADDRESS, +// WETH_ADDRESS, +// WPOL_VAULT_ADDRESS, +// } from "../../../helpers/constants"; +// import { expectZeroErc20Balances } from "../../../helpers/erc20"; +// import { executeAction } from "../../../helpers/executeAction"; +// import { expectOnlyAllowedApprovals } from "../../../helpers/logs"; +// import { getMorphoVaultPosition } from "../../../helpers/morpho"; +// import { paraswapSnapshotTest } from "../../snapshots/paraswapSnapshotTest"; + +// interface RunAaveV3PortfolioMigrationToVaultActionTestParameters { +// client: AnvilTestClient; + +// portfolioPercentage: number; +// maxSlippageTolerance: number; +// vaultAddress: Address; + +// // Must be correctly collateralized +// initialPositions: { assetAddress: Address; supplyAmount: bigint; borrowAmount: bigint }[]; + +// minVaultPosition: bigint; // In vault asset +// } + +// async function runAaveV3PortfolioMigrationToVaultActionTest({ +// client, + +// portfolioPercentage, +// maxSlippageTolerance, +// vaultAddress, + +// initialPositions, +// minVaultPosition, +// }: RunAaveV3PortfolioMigrationToVaultActionTestParameters) { +// // Arrange +// const collateralPositions = initialPositions.filter((p) => p.supplyAmount > 0n); +// const borrowPositions = initialPositions.filter((p) => p.borrowAmount > 0n); + +// for (const p of collateralPositions) { +// await dealAndSupplyToAaveV3(client, p.assetAddress, p.supplyAmount, true); +// } +// for (const p of borrowPositions) { +// await borrowFromAaveV3(client, p.assetAddress, p.borrowAmount); +// } + +// // Act +// const action = await aaveV3PortfolioMigrationToVaultAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage, +// maxSlippageTolerance, + +// vaultAddress, +// }); +// const logs = await executeAction(client, action); + +// // Assert +// await expectOnlyAllowedApprovals(client, logs, client.account.address); // Make sure doesn't approve or permit anything unexpected + +// // Make sure no dust left anywhere +// for (const p of initialPositions) { +// await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], p.assetAddress); +// } + +// const positionBalance = await getMorphoVaultPosition(client, vaultAddress); +// expect(positionBalance).toBeGreaterThanOrEqual(minVaultPosition); +// } + +// const initialPositions = [ +// { assetAddress: USDC_ADDRESS, supplyAmount: parseUnits("1000", 6), borrowAmount: parseUnits("10", 6) }, +// { assetAddress: USDT_ADDRESS, supplyAmount: parseUnits("2000", 6), borrowAmount: parseUnits("500", 6) }, +// { assetAddress: WETH_ADDRESS, supplyAmount: parseEther("1"), borrowAmount: parseEther("0") }, +// { assetAddress: DAI_ADDRESS, supplyAmount: parseUnits("0", 18), borrowAmount: parseUnits("2000", 18) }, +// ]; + +// describe("aaveV3PortfolioMigrationToVaultAction", () => { +// describe("happy path", () => { +// paraswapSnapshotTest("partial migration, USDC vault", async ({ client }) => { +// await runAaveV3PortfolioMigrationToVaultActionTest({ +// client, + +// portfolioPercentage: 0.5, +// maxSlippageTolerance: 0.015, +// vaultAddress: USDC_VAULT_ADDRESS, + +// initialPositions, +// minVaultPosition: parseUnits("1387", 6), // Need to update if taking a new snapshot to reflect ETH price +// }); +// }); +// // paraswapSnapshotTest("full migration, USDC vault", async ({ client }) => { +// // await runAaveV3PortfolioMigrationToVaultActionTest({ +// // client, + +// // portfolioPercentage: 1, +// // maxSlippageTolerance: 0.015, +// // vaultAddress: USDC_VAULT_ADDRESS, + +// // initialPositions, +// // minVaultPosition: parseUnits("2775", 6), // Need to update if taking a new snapshot to reflect ETH price +// // }); +// // }); +// paraswapSnapshotTest("partial migration, WPOL vault", async ({ client }) => { +// await runAaveV3PortfolioMigrationToVaultActionTest({ +// client, + +// portfolioPercentage: 0.5, +// maxSlippageTolerance: 0.015, +// vaultAddress: WPOL_VAULT_ADDRESS, + +// initialPositions, +// minVaultPosition: parseUnits("5280", 18), // Need to update if taking a new snapshot to reflect ETH price +// }); +// }); +// // paraswapSnapshotTest("full migration, WPOL vault", async ({ client }) => { +// // await runAaveV3PortfolioMigrationToVaultActionTest({ +// // client, + +// // portfolioPercentage: 1, +// // maxSlippageTolerance: 0.015, +// // vaultAddress: WPOL_VAULT_ADDRESS, + +// // initialPositions, +// // minVaultPosition: parseUnits("10673", 18), // Need to update if taking a new snapshot to reflect ETH price +// // }); +// // }); +// }); + +// describe("sad path", () => { +// test("portfolio percentage is 0", async ({ client }) => { +// const action = await aaveV3PortfolioMigrationToVaultAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage: 0, +// maxSlippageTolerance: 0.015, + +// vaultAddress: WPOL_VAULT_ADDRESS, +// }); +// expect(action.status).toEqual("error"); + +// if (action.status == "error") { +// expect(action.message).toEqual( +// "Simulation Error: Portfolio percentage must be between 0 (exclusive) and 1 (inclusive)" +// ); +// } +// }); +// test("portfolio percentage is >1", async ({ client }) => { +// const action = await aaveV3PortfolioMigrationToVaultAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage: 1.1, +// maxSlippageTolerance: 0.015, + +// vaultAddress: WPOL_VAULT_ADDRESS, +// }); +// expect(action.status).toEqual("error"); + +// if (action.status == "error") { +// expect(action.message).toEqual( +// "Simulation Error: Portfolio percentage must be between 0 (exclusive) and 1 (inclusive)" +// ); +// } +// }); +// test("slippage is 0", async ({ client }) => { +// const action = await aaveV3PortfolioMigrationToVaultAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage: 0.5, +// maxSlippageTolerance: 0.0, + +// vaultAddress: WPOL_VAULT_ADDRESS, +// }); +// expect(action.status).toEqual("error"); + +// if (action.status == "error") { +// expect(action.message).toEqual("Simulation Error: Max slippage tolerance must be between 0 and 0.5"); +// } +// }); +// test("slippage is >0.5", async ({ client }) => { +// const action = await aaveV3PortfolioMigrationToVaultAction({ +// publicClient: client, +// accountAddress: client.account.address, + +// portfolioPercentage: 0.5, +// maxSlippageTolerance: 0.51, + +// vaultAddress: WPOL_VAULT_ADDRESS, +// }); +// expect(action.status).toEqual("error"); + +// if (action.status == "error") { +// expect(action.message).toEqual("Simulation Error: Max slippage tolerance must be between 0 and 0.5"); +// } +// }); +// }); +// }); describe("aaveV3PortfolioMigrationToVaultAction", () => { - describe("happy path", () => { - paraswapSnapshotTest("partial migration, USDC vault", async ({ client }) => { - await runAaveV3PortfolioMigrationToVaultActionTest({ - client, - - portfolioPercentage: 0.5, - maxSlippageTolerance: 0.015, - vaultAddress: USDC_VAULT_ADDRESS, - - initialPositions, - minVaultPosition: parseUnits("1387", 6), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - paraswapSnapshotTest("full migration, USDC vault", async ({ client }) => { - await runAaveV3PortfolioMigrationToVaultActionTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - vaultAddress: USDC_VAULT_ADDRESS, - - initialPositions, - minVaultPosition: parseUnits("2775", 6), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - paraswapSnapshotTest("partial migration, WPOL vault", async ({ client }) => { - await runAaveV3PortfolioMigrationToVaultActionTest({ - client, - - portfolioPercentage: 0.5, - maxSlippageTolerance: 0.015, - vaultAddress: WPOL_VAULT_ADDRESS, - - initialPositions, - minVaultPosition: parseUnits("5280", 18), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - paraswapSnapshotTest("full migration, WPOL vault", async ({ client }) => { - await runAaveV3PortfolioMigrationToVaultActionTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - vaultAddress: WPOL_VAULT_ADDRESS, - - initialPositions, - minVaultPosition: parseUnits("10673", 18), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - }); - - describe("sad path", () => { - test("portfolio percentage is 0", async ({ client }) => { - const action = await aaveV3PortfolioMigrationToVaultAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage: 0, - maxSlippageTolerance: 0.015, - - vaultAddress: WPOL_VAULT_ADDRESS, - }); - expect(action.status).toEqual("error"); - - if (action.status == "error") { - expect(action.message).toEqual( - "Simulation Error: Portfolio percentage must be between 0 (exclusive) and 1 (inclusive)" - ); - } - }); - test("portfolio percentage is >1", async ({ client }) => { - const action = await aaveV3PortfolioMigrationToVaultAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage: 1.1, - maxSlippageTolerance: 0.015, - - vaultAddress: WPOL_VAULT_ADDRESS, - }); - expect(action.status).toEqual("error"); - - if (action.status == "error") { - expect(action.message).toEqual( - "Simulation Error: Portfolio percentage must be between 0 (exclusive) and 1 (inclusive)" - ); - } - }); - test("slippage is 0", async ({ client }) => { - const action = await aaveV3PortfolioMigrationToVaultAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage: 0.5, - maxSlippageTolerance: 0.0, - - vaultAddress: WPOL_VAULT_ADDRESS, - }); - expect(action.status).toEqual("error"); - - if (action.status == "error") { - expect(action.message).toEqual("Simulation Error: Max slippage tolerance must be between 0 and 0.5"); - } - }); - test("slippage is >0.5", async ({ client }) => { - const action = await aaveV3PortfolioMigrationToVaultAction({ - publicClient: client, - accountAddress: client.account.address, - - portfolioPercentage: 0.5, - maxSlippageTolerance: 0.51, - - vaultAddress: WPOL_VAULT_ADDRESS, - }); - expect(action.status).toEqual("error"); - - if (action.status == "error") { - expect(action.message).toEqual("Simulation Error: Max slippage tolerance must be between 0 and 0.5"); - } - }); + test("unused", () => { + // Unused: satifies vitest }); }); diff --git a/test/unit/actions/migration/aaveV3VaultMigrationAction.test.ts b/test/unit/actions/migration/aaveV3VaultMigrationAction.test.ts index abed8a6..4c2c776 100644 --- a/test/unit/actions/migration/aaveV3VaultMigrationAction.test.ts +++ b/test/unit/actions/migration/aaveV3VaultMigrationAction.test.ts @@ -1,174 +1,183 @@ -import { AnvilTestClient } from "@morpho-org/test"; -import { Address, maxUint256, parseUnits } from "viem"; -import { describe, expect } from "vitest"; +// import { AnvilTestClient } from "@morpho-org/test"; +// import { Address, parseUnits } from "viem"; +// import { describe, expect } from "vitest"; -import { aaveV3VaultMigrationAction } from "@/actions/migration/aaveV3VaultMigrationAction"; -import { computeAmountWithRebasingMargin } from "@/actions/utils/math"; -import { AAVE_V3_MIGRATION_ADAPTER_ADDRESS, BUNDLER3_ADDRESS, GENERAL_ADAPTER_1_ADDRESS } from "@/utils/constants"; +import { describe, test } from "vitest"; -import { currentBlockTest as test } from "../../../config"; -import { dealAndSupplyToAaveV3, getAaveV3SupplyBalance } from "../../../helpers/aaveV3"; -import { USDC_ADDRESS } from "../../../helpers/constants"; -import { expectZeroErc20Balances } from "../../../helpers/erc20"; -import { executeAction } from "../../../helpers/executeAction"; -import { getMorphoVaultPosition } from "../../../helpers/morpho"; +// import { aaveV3VaultMigrationAction } from "@/actions/migration/aaveV3VaultMigrationAction"; +// import { computeAmountWithRebasingMargin } from "@/actions/utils/math"; +// import { AAVE_V3_MIGRATION_ADAPTER_ADDRESS, BUNDLER3_ADDRESS, GENERAL_ADAPTER_1_ADDRESS } from "@/utils/constants"; -const USDC_VAULT_ADDRESS = "0x781FB7F6d845E3bE129289833b04d43Aa8558c42"; +// import { currentBlockTest as test } from "../../../config"; +// import { dealAndSupplyToAaveV3, getAaveV3SupplyBalance } from "../../../helpers/aaveV3"; +// import { USDC_ADDRESS } from "../../../helpers/constants"; +// import { expectZeroErc20Balances } from "../../../helpers/erc20"; +// import { executeAction } from "../../../helpers/executeAction"; +// import { getMorphoVaultPosition } from "../../../helpers/morpho"; -interface RunVaultMigrationTestParameters { - client: AnvilTestClient; - vaultAddress: Address; - assetAddress: Address; - aaveSupplyAmount: bigint; - migrationAmount: bigint; // maxUint256 for full migration - delayBlocks: number; // delay between action preparation and execution - checks: { - aaveV3SupplyBalanceFinalLimits: { - min: bigint; - max: bigint; - }; - vaultPositionBalanceFinalLimits: { - min: bigint; - max: bigint; - }; - }; -} +// const USDC_VAULT_ADDRESS = "0x781FB7F6d845E3bE129289833b04d43Aa8558c42"; -async function runVaultMigrationTest({ - client, - vaultAddress, - assetAddress, - aaveSupplyAmount, - migrationAmount, // maxUint256 for full migration - delayBlocks, // delay between action preparation and execution - checks, -}: RunVaultMigrationTestParameters) { - // Arrange - await dealAndSupplyToAaveV3(client, assetAddress, aaveSupplyAmount, true); +// interface RunVaultMigrationTestParameters { +// client: AnvilTestClient; +// vaultAddress: Address; +// assetAddress: Address; +// aaveSupplyAmount: bigint; +// migrationAmount: bigint; // maxUint256 for full migration +// delayBlocks: number; // delay between action preparation and execution +// checks: { +// aaveV3SupplyBalanceFinalLimits: { +// min: bigint; +// max: bigint; +// }; +// vaultPositionBalanceFinalLimits: { +// min: bigint; +// max: bigint; +// }; +// }; +// } - // Act - const action = await aaveV3VaultMigrationAction({ - publicClient: client, - accountAddress: client.account.address, - vaultAddress, - amount: migrationAmount, - }); - await client.mine({ blocks: delayBlocks }); - await executeAction(client, action); +// async function runVaultMigrationTest({ +// client, +// vaultAddress, +// assetAddress, +// aaveSupplyAmount, +// migrationAmount, // maxUint256 for full migration +// delayBlocks, // delay between action preparation and execution +// checks, +// }: RunVaultMigrationTestParameters) { +// // Arrange +// await dealAndSupplyToAaveV3(client, assetAddress, aaveSupplyAmount, true); - // Assert - // Check aave v3 balances - const aaveV3SupplyBalanceFinal = await getAaveV3SupplyBalance(client, assetAddress); - expect(aaveV3SupplyBalanceFinal).toBeWithinRange( - checks.aaveV3SupplyBalanceFinalLimits.min, - checks.aaveV3SupplyBalanceFinalLimits.max - ); +// // Act +// const action = await aaveV3VaultMigrationAction({ +// publicClient: client, +// accountAddress: client.account.address, +// vaultAddress, +// amount: migrationAmount, +// }); +// await client.mine({ blocks: delayBlocks }); +// await executeAction(client, action); - // Check morpho balances - const morphoBalanceFinal = await getMorphoVaultPosition(client, vaultAddress); - expect(morphoBalanceFinal).toBeWithinRange( - checks.vaultPositionBalanceFinalLimits.min, - checks.vaultPositionBalanceFinalLimits.max - ); +// // Assert +// // Check aave v3 balances +// const aaveV3SupplyBalanceFinal = await getAaveV3SupplyBalance(client, assetAddress); +// expect(aaveV3SupplyBalanceFinal).toBeWithinRange( +// checks.aaveV3SupplyBalanceFinalLimits.min, +// checks.aaveV3SupplyBalanceFinalLimits.max +// ); - // Check no leftover balances - await expectZeroErc20Balances( - client, - [BUNDLER3_ADDRESS, AAVE_V3_MIGRATION_ADAPTER_ADDRESS!, GENERAL_ADAPTER_1_ADDRESS!], - assetAddress - ); -} +// // Check morpho balances +// const morphoBalanceFinal = await getMorphoVaultPosition(client, vaultAddress); +// expect(morphoBalanceFinal).toBeWithinRange( +// checks.vaultPositionBalanceFinalLimits.min, +// checks.vaultPositionBalanceFinalLimits.max +// ); -describe("aaveV3VaultMigrationAction", () => { - test("should migrate full position", async ({ client }) => { - const aaveSupplyAmount = parseUnits("1000000", 6); - const aaveV3SupplyBalanceFinalLimits = { min: BigInt(0), max: BigInt(0) }; - const vaultPositionBalanceFinalLimits = { - min: aaveSupplyAmount, - max: computeAmountWithRebasingMargin(aaveSupplyAmount), - }; - await runVaultMigrationTest({ - client, - vaultAddress: USDC_VAULT_ADDRESS, - assetAddress: USDC_ADDRESS, - aaveSupplyAmount, - migrationAmount: maxUint256, - delayBlocks: 0, - checks: { - aaveV3SupplyBalanceFinalLimits, - vaultPositionBalanceFinalLimits, - }, - }); - }); +// // Check no leftover balances +// await expectZeroErc20Balances( +// client, +// [BUNDLER3_ADDRESS, AAVE_V3_MIGRATION_ADAPTER_ADDRESS!, GENERAL_ADAPTER_1_ADDRESS!], +// assetAddress +// ); +// } - test("should migrate full position with <1 day delay", async ({ client }) => { - const aaveSupplyAmount = parseUnits("1000000", 6); - const aaveV3SupplyBalanceFinalLimits = { min: BigInt(0), max: BigInt(0) }; - const vaultPositionBalanceFinalLimits = { - min: aaveSupplyAmount, - max: computeAmountWithRebasingMargin(aaveSupplyAmount), - }; - await runVaultMigrationTest({ - client, - vaultAddress: USDC_VAULT_ADDRESS, - assetAddress: USDC_ADDRESS, - aaveSupplyAmount, - migrationAmount: maxUint256, - delayBlocks: 1000, - checks: { - aaveV3SupplyBalanceFinalLimits, - vaultPositionBalanceFinalLimits, - }, - }); - }); +// describe("aaveV3VaultMigrationAction", () => { +// // Disabled for now while migration features is turned off. Fails due to check against no maxUint256 input transfer +// // test("should migrate full position", async ({ client }) => { +// // const aaveSupplyAmount = parseUnits("1000000", 6); +// // const aaveV3SupplyBalanceFinalLimits = { min: BigInt(0), max: BigInt(0) }; +// // const vaultPositionBalanceFinalLimits = { +// // min: aaveSupplyAmount, +// // max: computeAmountWithRebasingMargin(aaveSupplyAmount), +// // }; +// // await runVaultMigrationTest({ +// // client, +// // vaultAddress: USDC_VAULT_ADDRESS, +// // assetAddress: USDC_ADDRESS, +// // aaveSupplyAmount, +// // migrationAmount: maxUint256, +// // delayBlocks: 0, +// // checks: { +// // aaveV3SupplyBalanceFinalLimits, +// // vaultPositionBalanceFinalLimits, +// // }, +// // }); +// // }); - test("should fail when migrating full position with long delay between creation and execution (rebasing/slippage casues failure)", async ({ - client, - }) => { - const aaveSupplyAmount = parseUnits("1000000", 6); - const aaveV3SupplyBalanceFinalLimits = { min: BigInt(0), max: BigInt(0) }; - const vaultPositionBalanceFinalLimits = { - min: aaveSupplyAmount, - max: computeAmountWithRebasingMargin(aaveSupplyAmount), - }; - await expect( - runVaultMigrationTest({ - client, - vaultAddress: USDC_VAULT_ADDRESS, - assetAddress: USDC_ADDRESS, - aaveSupplyAmount, - migrationAmount: maxUint256, - delayBlocks: 500000, - checks: { - aaveV3SupplyBalanceFinalLimits, - vaultPositionBalanceFinalLimits, - }, - }) - ).rejects.toThrow("action-tx-reverted"); - }); +// // test("should migrate full position with <1 day delay", async ({ client }) => { +// // const aaveSupplyAmount = parseUnits("1000000", 6); +// // const aaveV3SupplyBalanceFinalLimits = { min: BigInt(0), max: BigInt(0) }; +// // const vaultPositionBalanceFinalLimits = { +// // min: aaveSupplyAmount, +// // max: computeAmountWithRebasingMargin(aaveSupplyAmount), +// // }; +// // await runVaultMigrationTest({ +// // client, +// // vaultAddress: USDC_VAULT_ADDRESS, +// // assetAddress: USDC_ADDRESS, +// // aaveSupplyAmount, +// // migrationAmount: maxUint256, +// // delayBlocks: 1000, +// // checks: { +// // aaveV3SupplyBalanceFinalLimits, +// // vaultPositionBalanceFinalLimits, +// // }, +// // }); +// // }); + +// // test("should fail when migrating full position with long delay between creation and execution (rebasing/slippage casues failure)", async ({ +// // client, +// // }) => { +// // const aaveSupplyAmount = parseUnits("1000000", 6); +// // const aaveV3SupplyBalanceFinalLimits = { min: BigInt(0), max: BigInt(0) }; +// // const vaultPositionBalanceFinalLimits = { +// // min: aaveSupplyAmount, +// // max: computeAmountWithRebasingMargin(aaveSupplyAmount), +// // }; +// // await expect( +// // runVaultMigrationTest({ +// // client, +// // vaultAddress: USDC_VAULT_ADDRESS, +// // assetAddress: USDC_ADDRESS, +// // aaveSupplyAmount, +// // migrationAmount: maxUint256, +// // delayBlocks: 500000, +// // checks: { +// // aaveV3SupplyBalanceFinalLimits, +// // vaultPositionBalanceFinalLimits, +// // }, +// // }) +// // ).rejects.toThrow("action-tx-reverted"); +// // }); - test("should migrate partial position", async ({ client }) => { - const aaveSupplyAmount = parseUnits("1000000", 6); - const migrationAmount = aaveSupplyAmount / BigInt(4); - const aaveV3SupplyBalanceFinalLimits = { - min: aaveSupplyAmount - migrationAmount, - max: computeAmountWithRebasingMargin(aaveSupplyAmount - migrationAmount), - }; - const vaultPositionBalanceFinalLimits = { - min: migrationAmount - BigInt(1), // From rounding - max: computeAmountWithRebasingMargin(migrationAmount), - }; - await runVaultMigrationTest({ - client, - vaultAddress: USDC_VAULT_ADDRESS, - assetAddress: USDC_ADDRESS, - aaveSupplyAmount, - migrationAmount, - delayBlocks: 0, - checks: { - aaveV3SupplyBalanceFinalLimits, - vaultPositionBalanceFinalLimits, - }, - }); +// test("should migrate partial position", async ({ client }) => { +// const aaveSupplyAmount = parseUnits("1000000", 6); +// const migrationAmount = aaveSupplyAmount / BigInt(4); +// const aaveV3SupplyBalanceFinalLimits = { +// min: aaveSupplyAmount - migrationAmount, +// max: computeAmountWithRebasingMargin(aaveSupplyAmount - migrationAmount), +// }; +// const vaultPositionBalanceFinalLimits = { +// min: migrationAmount - BigInt(1), // From rounding +// max: computeAmountWithRebasingMargin(migrationAmount), +// }; +// await runVaultMigrationTest({ +// client, +// vaultAddress: USDC_VAULT_ADDRESS, +// assetAddress: USDC_ADDRESS, +// aaveSupplyAmount, +// migrationAmount, +// delayBlocks: 0, +// checks: { +// aaveV3SupplyBalanceFinalLimits, +// vaultPositionBalanceFinalLimits, +// }, +// }); +// }); +// }); + +describe("aaveV3VaultMigrationAction", () => { + test("unused", () => { + // Unused: satifies vitest }); }); diff --git a/test/unit/actions/subbundles/aaveV3PortfolioWindDownSubbundle.test.ts b/test/unit/actions/subbundles/aaveV3PortfolioWindDownSubbundle.test.ts index 5fa6c4b..6c6314b 100644 --- a/test/unit/actions/subbundles/aaveV3PortfolioWindDownSubbundle.test.ts +++ b/test/unit/actions/subbundles/aaveV3PortfolioWindDownSubbundle.test.ts @@ -1,5 +1,5 @@ import { AnvilTestClient } from "@morpho-org/test"; -import { Address, isAddressEqual, parseEther, parseUnits } from "viem"; +import { Address, isAddressEqual, parseUnits } from "viem"; import { readContract } from "viem/actions"; import { describe, expect } from "vitest"; @@ -11,7 +11,7 @@ import { import { createBundle } from "@/actions/utils/bundlerActions"; import { computeScaledAmount } from "@/actions/utils/math"; import { Action } from "@/actions/utils/types"; -import { AAVE_V3_POOL_ADDRESS_PROVIDER, AAVE_V3_UI_POOL_DATA_PROVIDER_ADDRESS, WBTC_ADDRESS } from "@/config"; +import { AAVE_V3_POOL_ADDRESS_PROVIDER, AAVE_V3_UI_POOL_DATA_PROVIDER_ADDRESS } from "@/config"; import { AAVE_V3_MIGRATION_ADAPTER_ADDRESS, BUNDLER3_ADDRESS, @@ -26,7 +26,7 @@ import { getAaveV3LoanBalance, getAaveV3SupplyBalance, } from "../../../helpers/aaveV3"; -import { DAI_ADDRESS, USDC_ADDRESS, USDT_ADDRESS, WETH_ADDRESS } from "../../../helpers/constants"; +import { DAI_ADDRESS, USDC_ADDRESS, USDT_ADDRESS } from "../../../helpers/constants"; import { expectZeroErc20Balances, getErc20BalanceOf } from "../../../helpers/erc20"; import { executeAction } from "../../../helpers/executeAction"; import { expectOnlyAllowedApprovals } from "../../../helpers/logs"; @@ -193,46 +193,46 @@ describe("aaveV3PortfolioWindDownSubbundle", () => { minOutputAssets: parseUnits("497", 6), }); }); - paraswapSnapshotTest("full wind down - supply in FLA only, output = FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: USDC_ADDRESS, - - initialPositions: [ - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: 0n, - }, - ], - - minOutputAssets: parseUnits("1000", 6), - }); - }); - paraswapSnapshotTest("full wind down - supply in FLA only, output != FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: USDT_ADDRESS, - - initialPositions: [ - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: 0n, - }, - ], - - minOutputAssets: parseUnits("998", 6), - }); - }); + // paraswapSnapshotTest("full wind down - supply in FLA only, output = FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: USDC_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: 0n, + // }, + // ], + + // minOutputAssets: parseUnits("1000", 6), + // }); + // }); + // paraswapSnapshotTest("full wind down - supply in FLA only, output != FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: USDT_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: 0n, + // }, + // ], + + // minOutputAssets: parseUnits("998", 6), + // }); + // }); paraswapSnapshotTest("partial wind down - output = FLA", async ({ client }) => { await runAaveV3PortfolioWindDownSubbundleTest({ @@ -284,56 +284,56 @@ describe("aaveV3PortfolioWindDownSubbundle", () => { minOutputAssets: parseUnits("992", 18), }); }); - paraswapSnapshotTest("full wind down - output = FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: USDC_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: 0n, - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: 0n, - }, - ], - - minOutputAssets: parseUnits("1986", 6), - }); - }); - paraswapSnapshotTest("full wind down - output != FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: DAI_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: 0n, - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: 0n, - }, - ], - - minOutputAssets: parseUnits("1986", 18), - }); - }); + // paraswapSnapshotTest("full wind down - output = FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: USDC_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: 0n, + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: 0n, + // }, + // ], + + // minOutputAssets: parseUnits("1986", 6), + // }); + // }); + // paraswapSnapshotTest("full wind down - output != FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: DAI_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: 0n, + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: 0n, + // }, + // ], + + // minOutputAssets: parseUnits("1986", 18), + // }); + // }); paraswapSnapshotTest("partial wind down - with dust (should ignore it)", async ({ client }) => { await runAaveV3PortfolioWindDownSubbundleTest({ @@ -361,31 +361,31 @@ describe("aaveV3PortfolioWindDownSubbundle", () => { }); }); - paraswapSnapshotTest("full wind down - with dust (should swap extra for it)", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: DAI_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: 1n, - borrowAmount: 0n, - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: 0n, - }, - ], - - minOutputAssets: parseUnits("990", 18), - }); - }); + // paraswapSnapshotTest("full wind down - with dust (should swap extra for it)", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: DAI_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: 1n, + // borrowAmount: 0n, + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: 0n, + // }, + // ], + + // minOutputAssets: parseUnits("990", 18), + // }); + // }); }); describe("supply and borrow", () => { @@ -439,56 +439,56 @@ describe("aaveV3PortfolioWindDownSubbundle", () => { minOutputAssets: parseUnits("245", 18), }); }); - paraswapSnapshotTest("full wind down - borrow in FLA only, output = FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: USDC_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: 0n, - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: 0n, - borrowAmount: parseUnits("500", 6), - }, - ], - - minOutputAssets: parseUnits("490", 6), - }); - }); - paraswapSnapshotTest("full wind down - borrow in FLA only, output != FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: DAI_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: 0n, - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: 0n, - borrowAmount: parseUnits("500", 6), - }, - ], - - minOutputAssets: parseUnits("490", 18), - }); - }); + // paraswapSnapshotTest("full wind down - borrow in FLA only, output = FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: USDC_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: 0n, + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: 0n, + // borrowAmount: parseUnits("500", 6), + // }, + // ], + + // minOutputAssets: parseUnits("490", 6), + // }); + // }); + // paraswapSnapshotTest("full wind down - borrow in FLA only, output != FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: DAI_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: 0n, + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: 0n, + // borrowAmount: parseUnits("500", 6), + // }, + // ], + + // minOutputAssets: parseUnits("490", 18), + // }); + // }); paraswapSnapshotTest("partial wind down - borrow and supply in FLA only, output = FLA", async ({ client }) => { await runAaveV3PortfolioWindDownSubbundleTest({ @@ -530,260 +530,260 @@ describe("aaveV3PortfolioWindDownSubbundle", () => { minOutputAssets: parseUnits("245", 18), }); }); - paraswapSnapshotTest("full wind down - borrow and supply in FLA only, output = FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: USDC_ADDRESS, - - initialPositions: [ - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - ], - - minOutputAssets: parseUnits("500", 6), - }); - }); - paraswapSnapshotTest("full wind down - borrow and supply in FLA only, output != FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: DAI_ADDRESS, - - initialPositions: [ - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - ], - - minOutputAssets: parseUnits("495", 18), - }); - }); - - paraswapSnapshotTest("partial wind down - output = FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 0.5, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: USDC_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: WETH_ADDRESS, - supplyAmount: parseEther("1"), - borrowAmount: 0n, - }, - { - assetAddress: DAI_ADDRESS, - supplyAmount: 0n, - borrowAmount: parseUnits("100", 18), - }, - ], - minOutputAssets: parseUnits("1590", 6), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - paraswapSnapshotTest("partial wind down - output != FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 0.5, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: DAI_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: WETH_ADDRESS, - supplyAmount: parseEther("1"), - borrowAmount: 0n, - }, - { - assetAddress: DAI_ADDRESS, - supplyAmount: 0n, - borrowAmount: parseUnits("100", 18), - }, - ], - minOutputAssets: parseUnits("1590", 18), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - - paraswapSnapshotTest("full wind down, output = FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: USDC_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: WETH_ADDRESS, - supplyAmount: parseEther("1"), - borrowAmount: 0n, - }, - { - assetAddress: DAI_ADDRESS, - supplyAmount: 0n, - borrowAmount: parseUnits("100", 18), - }, - ], - minOutputAssets: parseUnits("3180", 6), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - - paraswapSnapshotTest("full wind down - output != FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: USDC_ADDRESS, - outputAssetAddress: DAI_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: WETH_ADDRESS, - supplyAmount: parseEther("1"), - borrowAmount: 0n, - }, - { - assetAddress: DAI_ADDRESS, - supplyAmount: 0n, - borrowAmount: parseUnits("100", 18), - }, - ], - minOutputAssets: parseUnits("3180", 18), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - }); - - paraswapSnapshotTest("full wind down - output != FLA, WBTC FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: WBTC_ADDRESS, - outputAssetAddress: DAI_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("10000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: WETH_ADDRESS, - supplyAmount: parseEther("1"), - borrowAmount: 0n, - }, - { - assetAddress: DAI_ADDRESS, - supplyAmount: 0n, - borrowAmount: parseUnits("100", 18), - }, - ], - minOutputAssets: parseUnits("3180", 18), // Need to update if taking a new snapshot to reflect ETH price - }); - }); - - paraswapSnapshotTest("full wind down - output != FLA, WBTC FLA", async ({ client }) => { - await runAaveV3PortfolioWindDownSubbundleTest({ - client, - - portfolioPercentage: 1, - maxSlippageTolerance: 0.015, - flashLoanAssetAddress: WBTC_ADDRESS, - outputAssetAddress: DAI_ADDRESS, - - initialPositions: [ - { - assetAddress: USDT_ADDRESS, - supplyAmount: parseUnits("10000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: USDC_ADDRESS, - supplyAmount: parseUnits("1000", 6), - borrowAmount: parseUnits("500", 6), - }, - { - assetAddress: WETH_ADDRESS, - supplyAmount: parseEther("1"), - borrowAmount: 0n, - }, - { - assetAddress: DAI_ADDRESS, - supplyAmount: 0n, - borrowAmount: parseUnits("100", 18), - }, - { - assetAddress: WBTC_ADDRESS, - supplyAmount: parseUnits("0.1", 8), - borrowAmount: parseUnits("0.01", 8), - }, - ], - minOutputAssets: parseUnits("21150", 18), // Need to update if taking a new snapshot to reflect ETH price - }); + // paraswapSnapshotTest("full wind down - borrow and supply in FLA only, output = FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: USDC_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // ], + + // minOutputAssets: parseUnits("500", 6), + // }); + // }); + // paraswapSnapshotTest("full wind down - borrow and supply in FLA only, output != FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: DAI_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // ], + + // minOutputAssets: parseUnits("495", 18), + // }); + // }); + + // paraswapSnapshotTest("partial wind down - output = FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 0.5, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: USDC_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: WETH_ADDRESS, + // supplyAmount: parseEther("1"), + // borrowAmount: 0n, + // }, + // { + // assetAddress: DAI_ADDRESS, + // supplyAmount: 0n, + // borrowAmount: parseUnits("100", 18), + // }, + // ], + // minOutputAssets: parseUnits("1590", 6), // Need to update if taking a new snapshot to reflect ETH price + // }); + // }); + // paraswapSnapshotTest("partial wind down - output != FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 0.5, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: DAI_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: WETH_ADDRESS, + // supplyAmount: parseEther("1"), + // borrowAmount: 0n, + // }, + // { + // assetAddress: DAI_ADDRESS, + // supplyAmount: 0n, + // borrowAmount: parseUnits("100", 18), + // }, + // ], + // minOutputAssets: parseUnits("1590", 18), // Need to update if taking a new snapshot to reflect ETH price + // }); + // }); + + // paraswapSnapshotTest("full wind down, output = FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: USDC_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: WETH_ADDRESS, + // supplyAmount: parseEther("1"), + // borrowAmount: 0n, + // }, + // { + // assetAddress: DAI_ADDRESS, + // supplyAmount: 0n, + // borrowAmount: parseUnits("100", 18), + // }, + // ], + // minOutputAssets: parseUnits("3180", 6), // Need to update if taking a new snapshot to reflect ETH price + // }); + // }); + + // paraswapSnapshotTest("full wind down - output != FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: USDC_ADDRESS, + // outputAssetAddress: DAI_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: WETH_ADDRESS, + // supplyAmount: parseEther("1"), + // borrowAmount: 0n, + // }, + // { + // assetAddress: DAI_ADDRESS, + // supplyAmount: 0n, + // borrowAmount: parseUnits("100", 18), + // }, + // ], + // minOutputAssets: parseUnits("3180", 18), // Need to update if taking a new snapshot to reflect ETH price + // }); + // }); + // }); + + // paraswapSnapshotTest("full wind down - output != FLA, WBTC FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: WBTC_ADDRESS, + // outputAssetAddress: DAI_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("10000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: WETH_ADDRESS, + // supplyAmount: parseEther("1"), + // borrowAmount: 0n, + // }, + // { + // assetAddress: DAI_ADDRESS, + // supplyAmount: 0n, + // borrowAmount: parseUnits("100", 18), + // }, + // ], + // minOutputAssets: parseUnits("3180", 18), // Need to update if taking a new snapshot to reflect ETH price + // }); + // }); + + // paraswapSnapshotTest("full wind down - output != FLA, WBTC FLA", async ({ client }) => { + // await runAaveV3PortfolioWindDownSubbundleTest({ + // client, + + // portfolioPercentage: 1, + // maxSlippageTolerance: 0.015, + // flashLoanAssetAddress: WBTC_ADDRESS, + // outputAssetAddress: DAI_ADDRESS, + + // initialPositions: [ + // { + // assetAddress: USDT_ADDRESS, + // supplyAmount: parseUnits("10000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: USDC_ADDRESS, + // supplyAmount: parseUnits("1000", 6), + // borrowAmount: parseUnits("500", 6), + // }, + // { + // assetAddress: WETH_ADDRESS, + // supplyAmount: parseEther("1"), + // borrowAmount: 0n, + // }, + // { + // assetAddress: DAI_ADDRESS, + // supplyAmount: 0n, + // borrowAmount: parseUnits("100", 18), + // }, + // { + // assetAddress: WBTC_ADDRESS, + // supplyAmount: parseUnits("0.1", 8), + // borrowAmount: parseUnits("0.01", 8), + // }, + // ], + // minOutputAssets: parseUnits("21150", 18), // Need to update if taking a new snapshot to reflect ETH price + // }); }); }); diff --git a/test/unit/actions/subbundles/inputTransferSubbundle.test.ts b/test/unit/actions/subbundles/inputTransferSubbundle.test.ts index d212481..c054f62 100644 --- a/test/unit/actions/subbundles/inputTransferSubbundle.test.ts +++ b/test/unit/actions/subbundles/inputTransferSubbundle.test.ts @@ -6,9 +6,7 @@ import { describe, expect } from "vitest"; import { getSimulationState } from "@/actions/data/rpc/getSimulationState"; import { inputTransferSubbundle } from "@/actions/subbundles/inputTransferSubbundle"; import { createBundle } from "@/actions/utils/bundlerActions"; -import { computeAmountWithRebasingMargin } from "@/actions/utils/math"; import { Action } from "@/actions/utils/types"; -import { MIN_REMAINING_NATIVE_ASSET_BALANCE_AFTER_WRAPPING } from "@/config"; import { bigIntMax, bigIntMin } from "@/utils/bigint"; import { WRAPPED_NATIVE_ADDRESS } from "@/utils/constants"; @@ -91,44 +89,19 @@ async function runInputTransferSubbundleTest({ const walletFinalBalance = await getErc20BalanceOf(client, tokenAddress, client.account.address); const walletFinalNativeBalance = await getBalance(client, { address: client.account.address }); - if (amount == maxUint256) { - if (isWrappedNative && config.allowWrappingNativeAssets) { - // Full transfer, wrapping native if needed (native is always non-rebasing) - expect(walletFinalNativeBalance).toEqual(MIN_REMAINING_NATIVE_ASSET_BALANCE_AFTER_WRAPPING); - expect(walletFinalBalance).toEqual(0n); - expect(recipientFinalBalance).toEqual( - recipientInitialBalance + - initialWalletBalance + - initialNativeBalance - - MIN_REMAINING_NATIVE_ASSET_BALANCE_AFTER_WRAPPING - ); - } else { - expect(walletFinalBalance).toEqual(0n); - // Full balance transfer - const minChange = initialWalletBalance; + // Assert based on exact amount transferred (no maxUint256 support) + if (isWrappedNative && config.allowWrappingNativeAssets) { + const erc20AmountUsed = bigIntMin(amount, initialWalletBalance); + const wrappedNativeAmountUsed = bigIntMax(amount - erc20AmountUsed, 0n); - // Account to rebasing margin - const maxChange = config.tokenIsRebasing - ? computeAmountWithRebasingMargin(initialWalletBalance) - : initialWalletBalance; - - expect(recipientFinalBalance).toBeWithinRange( - recipientInitialBalance + minChange, - recipientInitialBalance + maxChange - ); - } + expect(recipientFinalBalance).toBe(recipientInitialBalance + amount); + expect(walletFinalBalance).toBe(initialWalletBalance - erc20AmountUsed); + expect(walletFinalNativeBalance).toBe(initialNativeBalance - wrappedNativeAmountUsed); } else { - if (isWrappedNative && config.allowWrappingNativeAssets) { - const erc20AmountUsed = bigIntMin(amount, initialWalletBalance); - const wrappedNativeAmountUsed = bigIntMax(amount - erc20AmountUsed, 0n); - - expect(recipientFinalBalance).toBe(recipientInitialBalance + amount); - expect(walletFinalBalance).toBe(initialWalletBalance - erc20AmountUsed); - expect(walletFinalNativeBalance).toBe(initialNativeBalance - wrappedNativeAmountUsed); - } else { - expect(recipientFinalBalance).toBe(recipientInitialBalance + amount); - expect(walletFinalBalance).toBe(initialWalletBalance - amount); - } + expect(recipientFinalBalance).toBe(recipientInitialBalance + amount); + // walletFinalBalance could be > (initialWalletBalance - amount) if rebasing added tokens + // but we only transfer the exact amount requested + expect(walletFinalBalance).toBeGreaterThanOrEqual(initialWalletBalance - amount); } } @@ -188,7 +161,7 @@ const successTestCases: ({ name: string } & Omit { ).rejects.toThrow("Insufficient wallet balance."); }); - test("full transfer rebasing margin exceeded", async ({ client }) => { + test("fails when amount is max uint256", async ({ client }) => { await expect( runInputTransferSubbundleTest({ client, @@ -581,15 +554,12 @@ describe("inputTransferSubbundle", () => { recipientAddress: RANDOM_ADDRESS, config: { accountSupportsSignatures: false, - tokenIsRebasing: true, + tokenIsRebasing: false, allowWrappingNativeAssets: false, }, - initialWalletBalance: parseEther("1000"), - beforeExecutionCb: async (client) => { - await client.deal({ erc20: USDC_ADDRESS, amount: parseEther("1000.4") }); - }, + initialWalletBalance: parseUnits("1000", 6), }) - ).rejects.toThrow("action-tx-reverted"); + ).rejects.toThrow("Max uint256 transfer is not supported"); }); }); }); diff --git a/test/unit/actions/vault/vaultSupplyAction.test.ts b/test/unit/actions/vault/vaultSupplyAction.test.ts index af13a36..3765edf 100644 --- a/test/unit/actions/vault/vaultSupplyAction.test.ts +++ b/test/unit/actions/vault/vaultSupplyAction.test.ts @@ -1,14 +1,18 @@ import { MathLib } from "@morpho-org/blue-sdk"; import { fetchVaultConfig, metaMorphoAbi } from "@morpho-org/blue-sdk-viem"; import { AnvilTestClient } from "@morpho-org/test"; -import { Address, isAddressEqual, maxUint256, parseEther, parseUnits, zeroAddress } from "viem"; +import { Address, erc20Abi, isAddressEqual, maxUint256, parseEther, parseUnits, zeroAddress } from "viem"; import { getBalance, readContract } from "viem/actions"; import { describe, expect } from "vitest"; import { vaultSupplyBundle } from "@/actions/vault/vaultSupplyAction"; -import { MIN_REMAINING_NATIVE_ASSET_BALANCE_AFTER_WRAPPING } from "@/config"; import { bigIntMax } from "@/utils/bigint"; -import { BUNDLER3_ADDRESS, SUPPORTED_ADDAPTERS, WRAPPED_NATIVE_ADDRESS } from "@/utils/constants"; +import { + BUNDLER3_ADDRESS, + GENERAL_ADAPTER_1_ADDRESS, + SUPPORTED_ADDAPTERS, + WRAPPED_NATIVE_ADDRESS, +} from "@/utils/constants"; import { test } from "../../../config"; import { @@ -63,13 +67,17 @@ async function runVaultSupplyTest({ allowWrappingNativeAssets, }); await beforeExecutionCb?.(client); + + const nativeBalanceBeforeExecution = await getBalance(client, { address: client.account.address }); + const erc20BalanceBeforeExecution = await getErc20BalanceOf(client, assetAddress, client.account.address); + const logs = await executeAction(client, action); // Assert await expectOnlyAllowedApprovals(client, logs, client.account.address); // Make sure doesn't approve or permit anything unexpected await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, ...SUPPORTED_ADDAPTERS], assetAddress); // Make sure no funds left in bundler or used adapters - const positionBalance = await getMorphoVaultPosition(client, vaultAddress); + const positionAfterExecution = await getMorphoVaultPosition(client, vaultAddress); const walletErc20Balance = await getErc20BalanceOf(client, USDC_ADDRESS, client.account.address); const walletNativeBalance = await getBalance(client, { address: client.account.address }); @@ -77,22 +85,16 @@ async function runVaultSupplyTest({ const expectWrappingNative = isWrappedNative && allowWrappingNativeAssets; // Vault always rounds against the user, hence the 1 margin - if (supplyAmount === maxUint256) { - // Supply max when uint256 - const expectedPositionBalance = expectWrappingNative - ? dealAmount + initialNativeBalance - MIN_REMAINING_NATIVE_ASSET_BALANCE_AFTER_WRAPPING - : dealAmount; - expect(expectedPositionBalance).toBeWithinRange(expectedPositionBalance - BigInt(1), expectedPositionBalance); - expect(walletErc20Balance).toEqual(BigInt(0)); - expect(walletNativeBalance).toBe( - expectWrappingNative ? MIN_REMAINING_NATIVE_ASSET_BALANCE_AFTER_WRAPPING : initialNativeBalance - ); - } else { - const coveredByNative = expectWrappingNative ? bigIntMax(supplyAmount - dealAmount, 0n) : 0n; - expect(positionBalance).toBeWithinRange(supplyAmount - BigInt(1), supplyAmount); - expect(walletErc20Balance).toEqual(bigIntMax(dealAmount - supplyAmount, 0n)); - expect(walletNativeBalance).toEqual(initialNativeBalance - coveredByNative); - } + const coveredByNative = expectWrappingNative ? bigIntMax(supplyAmount - dealAmount, 0n) : 0n; + + const expectedPositionBalance = supplyAmount; + expect(positionAfterExecution.userAssetBalance).toBeWithinRange( + expectedPositionBalance - BigInt(1), + expectedPositionBalance + ); + + expect(walletErc20Balance).toEqual(bigIntMax(erc20BalanceBeforeExecution - supplyAmount, 0n)); + expect(walletNativeBalance).toEqual(nativeBalanceBeforeExecution - coveredByNative); } const successTestCases: ({ name: string } & Omit)[] = [ @@ -103,9 +105,9 @@ const successTestCases: ({ name: string } & Omit { // Even if we wait some time for extra interest accural @@ -127,25 +129,41 @@ const successTestCases: ({ name: string } & Omit { + await client.deal({ erc20: USDC_ADDRESS, amount: parseUnits("10000000", 6) }); + await client.writeContract({ + abi: erc20Abi, + address: USDC_ADDRESS, + functionName: "approve", + args: [GENERAL_ADAPTER_1_ADDRESS, maxUint256], + }); + }, + }, + { + name: "should increase position by supply amount only (full), and lead to no leftover in bundler/ga1 even if there is an increase in approval + balance before execution", + vaultAddress: USDC_VAULT_ADDRESS, + supplyAmount: parseUnits("200000", 6), + dealAmount: parseUnits("200000", 6), + beforeExecutionCb: async (client) => { + await client.deal({ erc20: USDC_ADDRESS, amount: parseUnits("10000000", 6) }); + await client.writeContract({ + abi: erc20Abi, + address: USDC_ADDRESS, + functionName: "approve", + args: [GENERAL_ADAPTER_1_ADDRESS, maxUint256], + }); + }, }, ]; @@ -236,5 +254,37 @@ describe("vaultSupplyAction", () => { }) ).rejects.toThrow("action-tx-reverted"); }); + + test("throws when amount equals max uint256", async ({ client }) => { + const vaultAddress = USDC_VAULT_ADDRESS; + const action = await vaultSupplyBundle({ + publicClient: client, + accountAddress: client.account.address, + vaultAddress, + supplyAmount: maxUint256, + allowWrappingNativeAssets: false, + }); + expect(action.status).toBe("error"); + + if (action.status === "error") { + expect(action.message).toBe("Supply amount cannot be greater than or equal to max uint256"); + } + }); + + test("throws when amount greater than max uint256", async ({ client }) => { + const vaultAddress = USDC_VAULT_ADDRESS; + const action = await vaultSupplyBundle({ + publicClient: client, + accountAddress: client.account.address, + vaultAddress, + supplyAmount: maxUint256 + 1n, + allowWrappingNativeAssets: false, + }); + expect(action.status).toBe("error"); + + if (action.status === "error") { + expect(action.message).toBe("Supply amount cannot be greater than or equal to max uint256"); + } + }); }); }); diff --git a/test/unit/actions/vault/vaultWithdrawAction.test.ts b/test/unit/actions/vault/vaultWithdrawAction.test.ts index 8970218..dc345d9 100644 --- a/test/unit/actions/vault/vaultWithdrawAction.test.ts +++ b/test/unit/actions/vault/vaultWithdrawAction.test.ts @@ -1,6 +1,6 @@ import { fetchVaultConfig } from "@morpho-org/blue-sdk-viem"; import { AnvilTestClient } from "@morpho-org/test"; -import { Address, maxUint256, parseUnits, zeroAddress } from "viem"; +import { Address, erc20Abi, maxUint256, parseUnits, zeroAddress } from "viem"; import { describe, expect } from "vitest"; import { vaultWithdrawAction } from "@/actions/vault/vaultWithdrawAction"; @@ -11,7 +11,11 @@ import { USDC_ADDRESS, USDC_VAULT_ADDRESS } from "../../../helpers/constants"; import { expectZeroErc20Balances, getErc20BalanceOf } from "../../../helpers/erc20"; import { executeAction } from "../../../helpers/executeAction"; import { expectOnlyAllowedApprovals } from "../../../helpers/logs"; -import { dealAndSupplyToMorphoVault, getMorphoVaultPosition } from "../../../helpers/morpho"; +import { + dealAndSupplyToMorphoVault, + getMorphoVaultPosition, + getMorphoVaultSharesToAssets, +} from "../../../helpers/morpho"; interface VaultWithdrawTestParameters { client: AnvilTestClient; @@ -40,6 +44,8 @@ async function runVaultWithdrawTest({ await client.setCode({ address: client.account.address, bytecode: "0x60006000fd" }); } + const positionBeforeBuild = await getMorphoVaultPosition(client, vaultAddress); + // Act const action = await vaultWithdrawAction({ publicClient: client, @@ -47,25 +53,37 @@ async function runVaultWithdrawTest({ vaultAddress, withdrawAmount, }); + await beforeExecutionCb?.(client); + + const erc20BalanceBeforeExecution = await getErc20BalanceOf(client, assetAddress, client.account.address); + const positionBeforeExecution = await getMorphoVaultPosition(client, vaultAddress); + const logs = await executeAction(client, action); // Assert await expectOnlyAllowedApprovals(client, logs, client.account.address); // Make sure doesn't approve or permit anything unexpected await expectZeroErc20Balances(client, [BUNDLER3_ADDRESS, GENERAL_ADAPTER_1_ADDRESS], assetAddress); // Make sure no funds left in bundler or used adapters - const positionBalance = await getMorphoVaultPosition(client, vaultAddress); - const walletBalance = await getErc20BalanceOf(client, USDC_ADDRESS, client.account.address); - - // Vault always rounds against the user, hence the 1 margin - if (withdrawAmount === maxUint256) { - // Withdraw max when uint256 - expect(positionBalance).toEqual(BigInt(0)); - expect(walletBalance).toBeGreaterThanOrEqual(initialSupplyAmount); - } else { - expect(positionBalance).toBeGreaterThanOrEqual(initialSupplyAmount - withdrawAmount - BigInt(1)); - expect(walletBalance).toEqual(withdrawAmount); - } + const positionAfterExecution = await getMorphoVaultPosition(client, vaultAddress); + const walletBalanceAfterExecution = await getErc20BalanceOf(client, USDC_ADDRESS, client.account.address); + + // When we requested a max withdraw, the withdraw amount is expected to be for the asset value of the shares the user had upon building action + const expectedWithdrawAmount = + withdrawAmount === maxUint256 + ? await getMorphoVaultSharesToAssets( + client, + vaultAddress, + client.account.address, + positionBeforeBuild.userShareBalance + ) + : withdrawAmount; + + const expectedPositionBalance = positionBeforeExecution.userAssetBalance - expectedWithdrawAmount; + expect(positionAfterExecution.userAssetBalance).toBeGreaterThanOrEqual(expectedPositionBalance - 1n); + + const expectedWalletBalance = erc20BalanceBeforeExecution + expectedWithdrawAmount; + expect(walletBalanceAfterExecution).toBeGreaterThanOrEqual(expectedWalletBalance - 1n); } const successTestCases: ({ name: string } & Omit)[] = [ @@ -85,6 +103,36 @@ const successTestCases: ({ name: string } & Omit { + await dealAndSupplyToMorphoVault(client, USDC_VAULT_ADDRESS, parseUnits("10000000000", 6)); + await client.writeContract({ + abi: erc20Abi, + address: USDC_VAULT_ADDRESS, + functionName: "approve", + args: [GENERAL_ADAPTER_1_ADDRESS, maxUint256], + }); + }, + }, + { + name: "should withdraw entire initial position for max uint256 withdraw amount even if increase in approval + share balance before execution", + vaultAddress: USDC_VAULT_ADDRESS, + initialSupplyAmount: parseUnits("123456", 6), + withdrawAmount: maxUint256, + beforeExecutionCb: async (client) => { + await dealAndSupplyToMorphoVault(client, USDC_VAULT_ADDRESS, parseUnits("10000000000", 6)); + await client.writeContract({ + abi: erc20Abi, + address: USDC_VAULT_ADDRESS, + functionName: "approve", + args: [GENERAL_ADAPTER_1_ADDRESS, maxUint256], + }); + }, + }, ]; describe("vaultWithdrawAction", () => { diff --git a/test/unit/paraswap/paraswapAdapterExactBuy.test.ts b/test/unit/paraswap/paraswapAdapterExactBuy.test.ts index d5bce4f..c5434be 100644 --- a/test/unit/paraswap/paraswapAdapterExactBuy.test.ts +++ b/test/unit/paraswap/paraswapAdapterExactBuy.test.ts @@ -22,7 +22,6 @@ const currentBlock = await polygonClient.getBlock(); export const test = createViemTest(polygon, { forkUrl: process.env.NEXT_PUBLIC_RPC_URL_1!, forkBlockNumber: currentBlock.number, - hardfork: "Latest", }); interface ParaswapAdapterExactBuyTest { diff --git a/test/unit/paraswap/paraswapAdapterExactSell.test.ts b/test/unit/paraswap/paraswapAdapterExactSell.test.ts index f51c16a..bba639c 100644 --- a/test/unit/paraswap/paraswapAdapterExactSell.test.ts +++ b/test/unit/paraswap/paraswapAdapterExactSell.test.ts @@ -23,7 +23,6 @@ const currentBlock = await polygonClient.getBlock(); export const test = createViemTest(polygon, { forkUrl: process.env.NEXT_PUBLIC_RPC_URL_1!, forkBlockNumber: currentBlock.number, - hardfork: "Latest", }); interface ParaswapAdapterExactSellTest { diff --git a/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral - contract caller.json b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral - contract caller.json new file mode 100644 index 0000000..4017121 --- /dev/null +++ b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral - contract caller.json @@ -0,0 +1,38 @@ +{ + "blockNumber": { + "__bigint__": "78716919" + }, + "paraswapExactBuyQuotes": {}, + "paraswapExactBuyTxPayloads": { + "e96a08e314d26046eade7a384433fcbed20a5699e5d8f91e32a76f9c0a75f46a": { + "augustus": "0x6A000F20005980200259B80c5102003040001068", + "calldata": "0x7f4576750000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6190000000000000000000000000000000000000000000000000000000521519e05000000000000000000000000000000000000000000000000560ad326a76bfc0000000000000000000000000000000000000000000000000000000004e6bb2c3fb3fe1219e88d4196aa272c21689d1a8400000000000000000000000004b11fff0000000000000000000000000000000000000000000000000000000000000000cc3e7c85bb0ee4f09380e041fee95a0caedd4a029400000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008200000016000000000000000000000012000000000000001340000000000000640f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f600000000000000000000000000000000000000000000000000dc4bb858123bf5c00000000000000000000000000000000000000000000000000000000c8bf393e00000000000000000000000000000000000000000000000000000000000000287ceb23fd6bc0add59e62ac25578270cff1b9f6193c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000000016000000000000000000000012000000000000001370000000000000a28e592427a0aece92de3edee1f18e0157c058615640140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f60000000000000000000000000000000000000000000000000165e88ae91fa3ef60000000000000000000000000000000000000000000000000000000146232c64000000000000000000000000000000000000000000000000000000000000002b7ceb23fd6bc0add59e62ac25578270cff1b9f6190001f43c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000180000000000000000000000120000000000000014e0000000000000c80e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f600000000000000000000000000000000000000000000000001b88957d025ffeb80000000000000000000000000000000000000000000000000000000191b034ef00000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f619000bb8c2132d05d31c914a87c6611c10748aeb04b58e8f0000643c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000000000000000000016000000000000000000000012000000000000001480000000000000190f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f60000000000000000000000000000000000000000000000000037112afa04bffd700000000000000000000000000000000000000000000000000000000322a9936000000000000000000000000000000000000000000000000000000000000003c7ceb23fd6bc0add59e62ac25578270cff1b9f619c2132d05d31c914a87c6611c10748aeb04b58e8f3c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000180000000000000000000000120000000000000014e0000000000000898e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f6000000000000000000000000000000000000000000000000012ede6c5f1a1ff1f0000000000000000000000000000000000000000000000000000000113fdf87800000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f6190001f41bfd67037b42cf73acf2047067bd4f2c47d9bfd60001f43c499c542cef5e3811e1192ce70d8cc03d5c3359000000000000000000000000000000000000000000000000000000000000", + "offsets": { + "exactAmount": { + "__bigint__": "132" + }, + "limitAmount": { + "__bigint__": "100" + }, + "quotedAmount": { + "__bigint__": "164" + } + }, + "quoteSrcTokenAmount": { + "__bigint__": "21050895423" + }, + "maxSrcTokenAmount": { + "__bigint__": "22033833477" + }, + "inputs": { + "srcTokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + "destTokenAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", + "exactDestTokenAmount": { + "__bigint__": "6199999999999998976" + } + } + } + }, + "paraswapExactSellQuotes": {}, + "paraswapExactSellTxPayloads": {} +} \ No newline at end of file diff --git a/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral - eoa caller.json b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral - eoa caller.json new file mode 100644 index 0000000..33518ca --- /dev/null +++ b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral - eoa caller.json @@ -0,0 +1,38 @@ +{ + "blockNumber": { + "__bigint__": "78716919" + }, + "paraswapExactBuyQuotes": {}, + "paraswapExactBuyTxPayloads": { + "e96a08e314d26046eade7a384433fcbed20a5699e5d8f91e32a76f9c0a75f46a": { + "augustus": "0x6A000F20005980200259B80c5102003040001068", + "calldata": "0x7f4576750000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6190000000000000000000000000000000000000000000000000000000521519e05000000000000000000000000000000000000000000000000560ad326a76bfc0000000000000000000000000000000000000000000000000000000004e6e02086b4587fc49ee842c787285dc69762659c00000000000000000000000004b11ff90000000000000000000000000000000000000000000000000000000000000000cc3e7c85bb0ee4f09380e041fee95a0caedd4a029400000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008200000016000000000000000000000012000000000000001340000000000000640f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f540000000000000000000000000000000000000000000000000dc44abe812fff5c00000000000000000000000000000000000000000000000000000000c8ca44f200000000000000000000000000000000000000000000000000000000000000287ceb23fd6bc0add59e62ac25578270cff1b9f6193c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000000016000000000000000000000012000000000000001370000000000000960e592427a0aece92de3edee1f18e0157c058615640140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f5400000000000000000000000000000000000000000000000014a6701dc1c7ff0a000000000000000000000000000000000000000000000000000000012d161ed9000000000000000000000000000000000000000000000000000000000000002b7ceb23fd6bc0add59e62ac25578270cff1b9f6190001f43c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000180000000000000000000000120000000000000014e0000000000000d48e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f540000000000000000000000000000000000000000000000001d411ed4d285fea400000000000000000000000000000000000000000000000000000001aad3743e00000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f619000bb8c2132d05d31c914a87c6611c10748aeb04b58e8f0000643c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000000000000000000016000000000000000000000012000000000000001480000000000000190f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f54000000000000000000000000000000000000000000000000037112afa04bffd70000000000000000000000000000000000000000000000000000000032318d14000000000000000000000000000000000000000000000000000000000000003c7ceb23fd6bc0add59e62ac25578270cff1b9f619c2132d05d31c914a87c6611c10748aeb04b58e8f3c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000180000000000000000000000120000000000000014e0000000000000898e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069176f5400000000000000000000000000000000000000000000000012ede6c5f1a1ff1f0000000000000000000000000000000000000000000000000000000113fabb6900000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f6190001f41bfd67037b42cf73acf2047067bd4f2c47d9bfd60001f43c499c542cef5e3811e1192ce70d8cc03d5c3359000000000000000000000000000000000000000000000000000000000000", + "offsets": { + "exactAmount": { + "__bigint__": "132" + }, + "limitAmount": { + "__bigint__": "100" + }, + "quotedAmount": { + "__bigint__": "164" + } + }, + "quoteSrcTokenAmount": { + "__bigint__": "21053317254" + }, + "maxSrcTokenAmount": { + "__bigint__": "22033833477" + }, + "inputs": { + "srcTokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + "destTokenAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", + "exactDestTokenAmount": { + "__bigint__": "6199999999999998976" + } + } + } + }, + "paraswapExactSellQuotes": {}, + "paraswapExactSellTxPayloads": {} +} \ No newline at end of file diff --git a/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral and increase in approval + balance before execution - contract caller.json b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral and increase in approval + balance before execution - contract caller.json new file mode 100644 index 0000000..398757d --- /dev/null +++ b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral and increase in approval + balance before execution - contract caller.json @@ -0,0 +1,38 @@ +{ + "blockNumber": { + "__bigint__": "78719023" + }, + "paraswapExactBuyQuotes": {}, + "paraswapExactBuyTxPayloads": { + "e96a08e314d26046eade7a384433fcbed20a5699e5d8f91e32a76f9c0a75f46a": { + "augustus": "0x6A000F20005980200259B80c5102003040001068", + "calldata": "0x7f4576750000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f619000000000000000000000000000000000000000000000000000000053523c399000000000000000000000000000000000000000000000000560ad326a76bfc0000000000000000000000000000000000000000000000000000000004f7ad9717c9de47b511ab426798bb95689e96a96c00000000000000000000000004b128590000000000000000000000000000000000000000000000000000000000000000cc3e7c85bb0ee4f09380e041fee95a0caedd4a0294000000000000000000000000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000082000000160000000000000000000000120000000000000013400000000000003e8f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069178015000000000000000000000000000000000000000000000000089a765390c41f9a000000000000000000000000000000000000000000000000000000007f2dedad00000000000000000000000000000000000000000000000000000000000000287ceb23fd6bc0add59e62ac25578270cff1b9f6193c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000160000000000000000000000120000000000000013700000000000007d0e592427a0aece92de3edee1f18e0157c058615640140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069178015000000000000000000000000000000000000000000000000113595d1a175df3300000000000000000000000000000000000000000000000000000000fe4723e7000000000000000000000000000000000000000000000000000000000000002b7ceb23fd6bc0add59e62ac25578270cff1b9f6190001f43c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000180000000000000000000000120000000000000014e0000000000001450e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f08004010000000000000000000000000000000000000000000000000000000000691780150000000000000000000000000000000000000000000000002cbdf2eb23dbfdeb000000000000000000000000000000000000000000000000000000029553884a00000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f619000bb8c2132d05d31c914a87c6611c10748aeb04b58e8f0000643c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000000000000000160000000000000000000000120000000000000014800000000000000c8f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f080040100000000000000000000000000000000000000000000000000000000006917801500000000000000000000000000000000000000000000000001b88957d025ffec00000000000000000000000000000000000000000000000000000000196cad73000000000000000000000000000000000000000000000000000000000000003c7ceb23fd6bc0add59e62ac25578270cff1b9f619c2132d05d31c914a87c6611c10748aeb04b58e8f3c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000180000000000000000000000120000000000000014e0000000000000640e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f08004010000000000000000000000000000000000000000000000000000000000691780150000000000000000000000000000000000000000000000000dc44abe812fff5c00000000000000000000000000000000000000000000000000000000cb784fc600000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f6190001f41bfd67037b42cf73acf2047067bd4f2c47d9bfd60001f43c499c542cef5e3811e1192ce70d8cc03d5c3359000000000000000000000000000000000000000000000000000000000000", + "offsets": { + "exactAmount": { + "__bigint__": "132" + }, + "limitAmount": { + "__bigint__": "100" + }, + "quotedAmount": { + "__bigint__": "164" + } + }, + "quoteSrcTokenAmount": { + "__bigint__": "21335217943" + }, + "maxSrcTokenAmount": { + "__bigint__": "22366372761" + }, + "inputs": { + "srcTokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + "destTokenAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", + "exactDestTokenAmount": { + "__bigint__": "6199999999999998976" + } + } + } + }, + "paraswapExactSellQuotes": {}, + "paraswapExactSellTxPayloads": {} +} \ No newline at end of file diff --git a/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral and increase in approval + balance before execution - eoa caller.json b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral and increase in approval + balance before execution - eoa caller.json new file mode 100644 index 0000000..96e4a4a --- /dev/null +++ b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with exact wallet balance collateral and increase in approval + balance before execution - eoa caller.json @@ -0,0 +1,38 @@ +{ + "blockNumber": { + "__bigint__": "78719023" + }, + "paraswapExactBuyQuotes": {}, + "paraswapExactBuyTxPayloads": { + "e96a08e314d26046eade7a384433fcbed20a5699e5d8f91e32a76f9c0a75f46a": { + "augustus": "0x6A000F20005980200259B80c5102003040001068", + "calldata": "0x7f4576750000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f619000000000000000000000000000000000000000000000000000000053523c399000000000000000000000000000000000000000000000000560ad326a76bfc0000000000000000000000000000000000000000000000000000000004f7ad8202039641b58492464794f90c3ffbb31dd500000000000000000000000004b128520000000000000000000000000000000000000000000000000000000000000000cc3e7c85bb0ee4f09380e041fee95a0caedd4a0294000000000000000000000000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000082000000160000000000000000000000120000000000000013400000000000003e8f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069178005000000000000000000000000000000000000000000000000089a765390c41f9a000000000000000000000000000000000000000000000000000000007f2dedad00000000000000000000000000000000000000000000000000000000000000287ceb23fd6bc0add59e62ac25578270cff1b9f6193c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000160000000000000000000000120000000000000013700000000000007d0e592427a0aece92de3edee1f18e0157c058615640140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069178005000000000000000000000000000000000000000000000000113595d1a175df3300000000000000000000000000000000000000000000000000000000fe4723e7000000000000000000000000000000000000000000000000000000000000002b7ceb23fd6bc0add59e62ac25578270cff1b9f6190001f43c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000180000000000000000000000120000000000000014e0000000000001450e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f08004010000000000000000000000000000000000000000000000000000000000691780050000000000000000000000000000000000000000000000002cbdf2eb23dbfdeb000000000000000000000000000000000000000000000000000000029553884a00000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f619000bb8c2132d05d31c914a87c6611c10748aeb04b58e8f0000643c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000000000000000160000000000000000000000120000000000000014800000000000000c8f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f080040100000000000000000000000000000000000000000000000000000000006917800500000000000000000000000000000000000000000000000001b88957d025ffec00000000000000000000000000000000000000000000000000000000196c985e000000000000000000000000000000000000000000000000000000000000003c7ceb23fd6bc0add59e62ac25578270cff1b9f619c2132d05d31c914a87c6611c10748aeb04b58e8f3c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000180000000000000000000000120000000000000014e0000000000000640e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f08004010000000000000000000000000000000000000000000000000000000000691780050000000000000000000000000000000000000000000000000dc44abe812fff5c00000000000000000000000000000000000000000000000000000000cb784fc600000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f6190001f41bfd67037b42cf73acf2047067bd4f2c47d9bfd60001f43c499c542cef5e3811e1192ce70d8cc03d5c3359000000000000000000000000000000000000000000000000000000000000", + "offsets": { + "exactAmount": { + "__bigint__": "132" + }, + "limitAmount": { + "__bigint__": "100" + }, + "quotedAmount": { + "__bigint__": "164" + } + }, + "quoteSrcTokenAmount": { + "__bigint__": "21335212546" + }, + "maxSrcTokenAmount": { + "__bigint__": "22366372761" + }, + "inputs": { + "srcTokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + "destTokenAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", + "exactDestTokenAmount": { + "__bigint__": "6199999999999998976" + } + } + } + }, + "paraswapExactSellQuotes": {}, + "paraswapExactSellTxPayloads": {} +} \ No newline at end of file diff --git a/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with partial wallet balance collateral and increase in approval + balance before execution - contract caller.json b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with partial wallet balance collateral and increase in approval + balance before execution - contract caller.json new file mode 100644 index 0000000..646904e --- /dev/null +++ b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with partial wallet balance collateral and increase in approval + balance before execution - contract caller.json @@ -0,0 +1,38 @@ +{ + "blockNumber": { + "__bigint__": "78719023" + }, + "paraswapExactBuyQuotes": {}, + "paraswapExactBuyTxPayloads": { + "e96a08e314d26046eade7a384433fcbed20a5699e5d8f91e32a76f9c0a75f46a": { + "augustus": "0x6A000F20005980200259B80c5102003040001068", + "calldata": "0x7f4576750000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61900000000000000000000000000000000000000000000000000000000ec8658600000000000000000000000000000000000000000000000000f43fc2c04ee000000000000000000000000000000000000000000000000000000000000e151cc322e704d3fe57b483b89d406a25a973eab00000000000000000000000004b128570000000000000000000000000000000000000000000000000000000000000000cc3e7c85bb0ee4f09380e041fee95a0caedd4a029400000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000009a000000160000000000000000000000120000000000000013400000000000004b0f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f080040100000000000000000000000000000000000000000000000000000000006917801100000000000000000000000000000000000000000000000001d5034e8de19000000000000000000000000000000000000000000000000000000000001b0a85a200000000000000000000000000000000000000000000000000000000000000287ceb23fd6bc0add59e62ac25578270cff1b9f6193c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000160000000000000000000000120000000000000013700000000000000c8e592427a0aece92de3edee1f18e0157c058615640140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069178011000000000000000000000000000000000000000000000000004e32e34c26b000000000000000000000000000000000000000000000000000000000000481a7a9000000000000000000000000000000000000000000000000000000000000002b7ceb23fd6bc0add59e62ac25578270cff1b9f619000bb83c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000016000000000000000000000012000000000000001370000000000000c80e592427a0aece92de3edee1f18e0157c058615640140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f080040100000000000000000000000000000000000000000000000000000000006917801100000000000000000000000000000000000000000000000004e2761fd650c000000000000000000000000000000000000000000000000000000000004819b4f4000000000000000000000000000000000000000000000000000000000000002b7ceb23fd6bc0add59e62ac25578270cff1b9f6190001f43c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000180000000000000000000000120000000000000014e0000000000000d48e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f08004010000000000000000000000000000000000000000000000000000000000691780110000000000000000000000000000000000000000000000000530b704b9ff0000000000000000000000000000000000000000000000000000000000004c9aa16e00000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f6190001f4c2132d05d31c914a87c6611c10748aeb04b58e8f0000643c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000000000000000160000000000000000000000120000000000000014800000000000000c8f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069178011000000000000000000000000000000000000000000000000004e28e2290f0000000000000000000000000000000000000000000000000000000000000481e6d6000000000000000000000000000000000000000000000000000000000000003c7ceb23fd6bc0add59e62ac25578270cff1b9f619c2132d05d31c914a87c6611c10748aeb04b58e8f3c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000180000000000000000000000120000000000000014e0000000000000708e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f080040100000000000000000000000000000000000000000000000000000000006917801100000000000000000000000000000000000000000000000002bf6ff37187000000000000000000000000000000000000000000000000000000000000288f61af00000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f6190001f41bfd67037b42cf73acf2047067bd4f2c47d9bfd60001f43c499c542cef5e3811e1192ce70d8cc03d5c3359000000000000000000000000000000000000000000000000000000000000", + "offsets": { + "exactAmount": { + "__bigint__": "132" + }, + "limitAmount": { + "__bigint__": "100" + }, + "quotedAmount": { + "__bigint__": "164" + } + }, + "quoteSrcTokenAmount": { + "__bigint__": "3780234290" + }, + "maxSrcTokenAmount": { + "__bigint__": "3968227424" + }, + "inputs": { + "srcTokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + "destTokenAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", + "exactDestTokenAmount": { + "__bigint__": "1100000000000000000" + } + } + } + }, + "paraswapExactSellQuotes": {}, + "paraswapExactSellTxPayloads": {} +} \ No newline at end of file diff --git a/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with partial wallet balance collateral and increase in approval + balance before execution - eoa caller.json b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with partial wallet balance collateral and increase in approval + balance before execution - eoa caller.json new file mode 100644 index 0000000..99eb9a8 --- /dev/null +++ b/test/unit/snapshots/__snapshots__/marketLeveragedBorrowAction > happy path > leverage with partial wallet balance collateral and increase in approval + balance before execution - eoa caller.json @@ -0,0 +1,38 @@ +{ + "blockNumber": { + "__bigint__": "78719023" + }, + "paraswapExactBuyQuotes": {}, + "paraswapExactBuyTxPayloads": { + "e96a08e314d26046eade7a384433fcbed20a5699e5d8f91e32a76f9c0a75f46a": { + "augustus": "0x6A000F20005980200259B80c5102003040001068", + "calldata": "0x7f4576750000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61900000000000000000000000000000000000000000000000000000000ec8658600000000000000000000000000000000000000000000000000f43fc2c04ee000000000000000000000000000000000000000000000000000000000000e154e237a1cf77761bd140f79f698cc89ea47bae00000000000000000000000004b128360000000000000000000000000000000000000000000000000000000000000000cc3e7c85bb0ee4f09380e041fee95a0caedd4a029400000000000000000000000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000009a000000160000000000000000000000120000000000000013400000000000003e8f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069177fce0000000000000000000000000000000000000000000000000186ce6b0782f0000000000000000000000000000000000000000000000000000000000016886ca900000000000000000000000000000000000000000000000000000000000000287ceb23fd6bc0add59e62ac25578270cff1b9f6193c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000160000000000000000000000120000000000000013700000000000000c8e592427a0aece92de3edee1f18e0157c058615640140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069177fce000000000000000000000000000000000000000000000000004e20e1402f4000000000000000000000000000000000000000000000000000000000000481a7a9000000000000000000000000000000000000000000000000000000000000002b7ceb23fd6bc0add59e62ac25578270cff1b9f619000bb83c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000016000000000000000000000012000000000000001370000000000000bb8e592427a0aece92de3edee1f18e0157c058615640140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069177fce00000000000000000000000000000000000000000000000004946b411688d000000000000000000000000000000000000000000000000000000000004396ea39000000000000000000000000000000000000000000000000000000000000002b7ceb23fd6bc0add59e62ac25578270cff1b9f6190001f43c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000180000000000000000000000120000000000000014e0000000000001068e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069177fce00000000000000000000000000000000000000000000000006695a8d5e3b0000000000000000000000000000000000000000000000000000000000005ea62bc000000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f619000bb8c2132d05d31c914a87c6611c10748aeb04b58e8f0000643c499c542cef5e3811e1192ce70d8cc03d5c335900000000000000000000000000000000000000000000000000000000000000000160000000000000000000000120000000000000014800000000000000c8f5b509bb0909a69b1c207e495f687a596c168e120140008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069177fce000000000000000000000000000000000000000000000000004e28e2290f0000000000000000000000000000000000000000000000000000000000000481af8c000000000000000000000000000000000000000000000000000000000000003c7ceb23fd6bc0add59e62ac25578270cff1b9f619c2132d05d31c914a87c6611c10748aeb04b58e8f3c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000180000000000000000000000120000000000000014e0000000000000578e592427a0aece92de3edee1f18e0157c058615640160008400a400000000000300000000000000000000000000000000000000000000000000000000f28c0498000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000e5891850bb3f03090f03010000806f0800401000000000000000000000000000000000000000000000000000000000069177fce00000000000000000000000000000000000000000000000002231e2f1f690000000000000000000000000000000000000000000000000000000000001f8c086000000000000000000000000000000000000000000000000000000000000000427ceb23fd6bc0add59e62ac25578270cff1b9f6190001f41bfd67037b42cf73acf2047067bd4f2c47d9bfd60001f43c499c542cef5e3811e1192ce70d8cc03d5c3359000000000000000000000000000000000000000000000000000000000000", + "offsets": { + "exactAmount": { + "__bigint__": "132" + }, + "limitAmount": { + "__bigint__": "100" + }, + "quotedAmount": { + "__bigint__": "164" + } + }, + "quoteSrcTokenAmount": { + "__bigint__": "3780436535" + }, + "maxSrcTokenAmount": { + "__bigint__": "3968227424" + }, + "inputs": { + "srcTokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + "destTokenAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", + "exactDestTokenAmount": { + "__bigint__": "1100000000000000000" + } + } + } + }, + "paraswapExactSellQuotes": {}, + "paraswapExactSellTxPayloads": {} +} \ No newline at end of file