diff --git a/.changeset/weak-ideas-itch.md b/.changeset/weak-ideas-itch.md new file mode 100644 index 0000000000..137cf88e88 --- /dev/null +++ b/.changeset/weak-ideas-itch.md @@ -0,0 +1,5 @@ +--- +"@venusprotocol/evm": minor +--- + +update withdraw from matured Pendle vault flow diff --git a/.yarnrc.yml b/.yarnrc.yml index 267aaf7e59..406493bcde 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -4,3 +4,5 @@ nodeLinker: node-modules # In minutes. npmMinimalAgeGate: 10080 +npmPreapprovedPackages: + - "@venusprotocol/*" diff --git a/apps/evm/src/clients/api/__mocks__/index.ts b/apps/evm/src/clients/api/__mocks__/index.ts index 8903936d3c..03d02e1de7 100644 --- a/apps/evm/src/clients/api/__mocks__/index.ts +++ b/apps/evm/src/clients/api/__mocks__/index.ts @@ -818,6 +818,14 @@ export const useWithdrawFromPendleVault = vi.fn( }), ); +export const useWithdrawAtMaturityFromPendleVault = vi.fn( + (_variables: never, options?: MutationObserverOptions) => + useMutation({ + mutationFn: vi.fn(), + ...options, + }), +); + export const useBorrow = vi.fn((_variables: never, options?: MutationObserverOptions) => useMutation({ mutationFn: vi.fn(), diff --git a/apps/evm/src/clients/api/index.ts b/apps/evm/src/clients/api/index.ts index 41a1dc6470..c814192fb8 100644 --- a/apps/evm/src/clients/api/index.ts +++ b/apps/evm/src/clients/api/index.ts @@ -41,6 +41,7 @@ export * from './mutations/useSupplyTradePositionCollateral'; export * from './mutations/useWithdrawTradePositionCollateral'; export * from './mutations/useRepayWithCollateral'; export * from './mutations/useStakeInPendleVault'; +export * from './mutations/useWithdrawAtMaturityFromPendleVault'; export * from './mutations/useWithdrawFromPendleVault'; // Queries export * from './queries/getVaiTreasuryPercentage'; diff --git a/apps/evm/src/clients/api/mutations/useWithdrawAtMaturityFromPendleVault/__tests__/index.spec.ts b/apps/evm/src/clients/api/mutations/useWithdrawAtMaturityFromPendleVault/__tests__/index.spec.ts new file mode 100644 index 0000000000..cd40cceec4 --- /dev/null +++ b/apps/evm/src/clients/api/mutations/useWithdrawAtMaturityFromPendleVault/__tests__/index.spec.ts @@ -0,0 +1,255 @@ +import fakeAccountAddress, { + altAddress as fakePoolComptrollerAddress, +} from '__mocks__/models/address'; +import BigNumber from 'bignumber.js'; +import { queryClient } from 'clients/api/queryClient'; +import { NULL_ADDRESS } from 'constants/address'; +import FunctionKey from 'constants/functionKey'; +import { useGetContractAddress } from 'hooks/useGetContractAddress'; +import { useSendTransaction } from 'hooks/useSendTransaction'; +import { useAnalytics } from 'libs/analytics'; +import { renderHook } from 'testUtils/render'; +import type { Mock } from 'vitest'; + +import { useWithdrawAtMaturityFromPendleVault } from '..'; + +vi.mock('libs/contracts'); + +const fakePendleMarketAddress = '0x1234567890abcdef1234567890abcdef12345678' as const; + +const fakeFromToken = { + address: '0xB9e0E753630434d7863528cc73CB7AC638a7c8ff', + decimals: 18, + symbol: 'XVS', +}; + +const fakeToToken = { + address: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', + decimals: 18, + isNative: true, + symbol: 'BNB', +}; + +const fakeVToken = { + address: '0x6d6F697e34145Bb95c54E77482d97cc261Dc237E', + decimals: 8, + symbol: 'vXVS', + underlyingToken: fakeFromToken, +}; + +const fakeAmountToken = new BigNumber('100000000'); + +const fakeOptions = { + gasless: true, + waitForConfirmation: true, +}; + +const mockCaptureAnalyticEvent = vi.fn(); + +describe('useWithdrawAtMaturityFromPendleVault', () => { + beforeEach(() => { + mockCaptureAnalyticEvent.mockClear(); + + (useAnalytics as Mock).mockImplementation(() => ({ + captureAnalyticEvent: mockCaptureAnalyticEvent, + })); + }); + + it('calls useSendTransaction with the correct parameters for redeemAtMaturity', async () => { + renderHook( + () => + useWithdrawAtMaturityFromPendleVault( + { + pendleMarketAddress: fakePendleMarketAddress, + poolComptrollerAddress: fakePoolComptrollerAddress, + }, + fakeOptions, + ), + { accountAddress: fakeAccountAddress }, + ); + + expect(useSendTransaction).toHaveBeenCalledWith({ + fn: expect.any(Function), + onConfirmed: expect.any(Function), + options: fakeOptions, + }); + + const { fn, onConfirmed } = (useSendTransaction as Mock).mock.calls[0][0]; + + const redeemInput = { + fromToken: fakeFromToken, + toToken: fakeToToken, + amountMantissa: fakeAmountToken, + vToken: fakeVToken, + }; + + expect(fn(redeemInput)).toMatchObject({ + address: '0xfakePendlePtVaultContractAddress', + functionName: 'redeemAtMaturity', + args: [ + fakePendleMarketAddress, + 100000000n, + { + tokenOut: NULL_ADDRESS, + minTokenOut: 0n, + tokenRedeemSy: NULL_ADDRESS, + pendleSwap: NULL_ADDRESS, + swapData: { + extCalldata: '0x', + extRouter: NULL_ADDRESS, + needScale: false, + swapType: 0, + }, + }, + ], + }); + + await onConfirmed({ input: redeemInput }); + + expect(mockCaptureAnalyticEvent.mock.calls[0]).toMatchInlineSnapshot(` + [ + "Pendle vault redeemAtMaturity", + { + "fromTokenAmountTokens": 1, + "fromTokenSymbol": "XVS", + "pendleMarketAddress": "0x1234567890abcdef1234567890abcdef12345678", + "priceImpactPercentage": 0, + "slippageTolerancePercentage": 0, + "toTokenAmountTokens": 1, + "toTokenSymbol": "BNB", + }, + ] + `); + + expect(queryClient.invalidateQueries).toHaveBeenCalledWith({ + queryKey: [FunctionKey.GET_POOLS], + }); + expect(queryClient.invalidateQueries).toHaveBeenCalledWith({ + queryKey: [FunctionKey.GET_FIXED_RATED_VAULTS], + }); + }); + + it('does not require vToken to build the transaction', async () => { + renderHook( + () => + useWithdrawAtMaturityFromPendleVault( + { + pendleMarketAddress: fakePendleMarketAddress, + }, + fakeOptions, + ), + { accountAddress: fakeAccountAddress }, + ); + + const { fn } = (useSendTransaction as Mock).mock.calls[0][0]; + + const redeemInput = { + fromToken: fakeFromToken, + toToken: { + ...fakeToToken, + isNative: false, + }, + amountMantissa: fakeAmountToken, + }; + + expect(fn(redeemInput)).toMatchObject({ + args: [ + fakePendleMarketAddress, + 100000000n, + expect.objectContaining({ + tokenOut: fakeToToken.address, + }), + ], + }); + }); + + it('tracks zero token amounts on confirmation when vToken is not provided', async () => { + renderHook( + () => + useWithdrawAtMaturityFromPendleVault( + { + pendleMarketAddress: fakePendleMarketAddress, + }, + fakeOptions, + ), + { accountAddress: fakeAccountAddress }, + ); + + const { onConfirmed } = (useSendTransaction as Mock).mock.calls[0][0]; + + const redeemInput = { + fromToken: fakeFromToken, + toToken: { + ...fakeToToken, + isNative: false, + }, + amountMantissa: fakeAmountToken, + }; + + await onConfirmed({ input: redeemInput }); + + expect(mockCaptureAnalyticEvent.mock.calls[0]).toMatchInlineSnapshot(` + [ + "Pendle vault redeemAtMaturity", + { + "fromTokenAmountTokens": 0, + "fromTokenSymbol": "XVS", + "pendleMarketAddress": "0x1234567890abcdef1234567890abcdef12345678", + "priceImpactPercentage": 0, + "slippageTolerancePercentage": 0, + "toTokenAmountTokens": 0, + "toTokenSymbol": "BNB", + }, + ] + `); + }); + + it('throws when pendle market address is missing', async () => { + renderHook( + () => + useWithdrawAtMaturityFromPendleVault( + { + pendleMarketAddress: NULL_ADDRESS, + }, + fakeOptions, + ), + { accountAddress: fakeAccountAddress }, + ); + + const { fn } = (useSendTransaction as Mock).mock.calls[0][0]; + + const redeemInput = { + fromToken: fakeFromToken, + toToken: fakeToToken, + amountMantissa: fakeAmountToken, + }; + + expect(() => fn(redeemInput)).toThrow('somethingWentWrong'); + }); + + it('throws when contract address could not be retrieved', async () => { + (useGetContractAddress as Mock).mockReturnValue({ address: undefined }); + + renderHook( + () => + useWithdrawAtMaturityFromPendleVault( + { + pendleMarketAddress: fakePendleMarketAddress, + }, + fakeOptions, + ), + { accountAddress: fakeAccountAddress }, + ); + + const { fn } = (useSendTransaction as Mock).mock.calls[0][0]; + + const redeemInput = { + fromToken: fakeFromToken, + toToken: fakeToToken, + amountMantissa: fakeAmountToken, + vToken: fakeVToken, + }; + + expect(() => fn(redeemInput)).toThrow('somethingWentWrong'); + }); +}); diff --git a/apps/evm/src/clients/api/mutations/useWithdrawAtMaturityFromPendleVault/index.ts b/apps/evm/src/clients/api/mutations/useWithdrawAtMaturityFromPendleVault/index.ts new file mode 100644 index 0000000000..4f95b8f1c8 --- /dev/null +++ b/apps/evm/src/clients/api/mutations/useWithdrawAtMaturityFromPendleVault/index.ts @@ -0,0 +1,100 @@ +import type { Address } from 'viem'; + +import { NULL_ADDRESS } from 'constants/address'; +import { useGetContractAddress } from 'hooks/useGetContractAddress'; +import { useSendTransaction } from 'hooks/useSendTransaction'; +import { useAnalytics } from 'libs/analytics'; +import { pendlePtVaultAbi } from 'libs/contracts'; +import { VError } from 'libs/errors'; +import { useAccountAddress, useChainId } from 'libs/wallet'; +import { convertMantissaToTokens } from 'utilities/convertMantissaToTokens'; +import { invalidatePendleVaultCaches } from 'utilities/invalidatePendleVaultCaches'; +import type { + PendlePtVaultWithdrawAtMaturityInput, + WithdrawAtMaturityOptions, +} from '../useWithdrawFromPendleVault/types'; + +export const useWithdrawAtMaturityFromPendleVault = ( + { + pendleMarketAddress, + poolComptrollerAddress, + }: { + pendleMarketAddress: Address; + poolComptrollerAddress?: Address; + }, + options?: Partial, +) => { + const { chainId } = useChainId(); + const { accountAddress } = useAccountAddress(); + const { captureAnalyticEvent } = useAnalytics(); + + const { address: pendlePtVaultContractAddress } = useGetContractAddress({ + name: 'PendlePtVault', + }); + + return useSendTransaction({ + fn: ({ amountMantissa, toToken }: PendlePtVaultWithdrawAtMaturityInput) => { + if (!pendlePtVaultContractAddress) { + throw new VError({ + type: 'unexpected', + code: 'somethingWentWrong', + }); + } + + if (pendleMarketAddress === NULL_ADDRESS) { + throw new VError({ + type: 'unexpected', + code: 'somethingWentWrong', + }); + } + + return { + abi: pendlePtVaultAbi, + address: pendlePtVaultContractAddress, + functionName: 'redeemAtMaturity' as const, + args: [ + pendleMarketAddress, + BigInt(amountMantissa.toFixed()), + { + tokenOut: toToken.isNative ? NULL_ADDRESS : toToken.address, + minTokenOut: 0n, + tokenRedeemSy: NULL_ADDRESS, + pendleSwap: NULL_ADDRESS, + swapData: { + swapType: 0, + extRouter: NULL_ADDRESS, + extCalldata: '0x', + needScale: false, + }, + }, + ], + } as const; + }, + onConfirmed: async ({ input }) => { + const convertedAmountTokens = input.vToken + ? convertMantissaToTokens({ + value: input.amountMantissa, + token: input.vToken, + }).toNumber() + : 0; + + captureAnalyticEvent('Pendle vault redeemAtMaturity', { + pendleMarketAddress, + fromTokenSymbol: input.fromToken.symbol, + fromTokenAmountTokens: convertedAmountTokens, + toTokenSymbol: input.toToken.symbol, + toTokenAmountTokens: convertedAmountTokens, + priceImpactPercentage: 0, + slippageTolerancePercentage: 0, + }); + + invalidatePendleVaultCaches({ + input, + chainId, + accountAddress, + poolComptrollerAddress, + }); + }, + options, + }); +}; diff --git a/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/__tests__/__snapshots__/index.spec.ts.snap b/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/__tests__/__snapshots__/index.spec.ts.snap deleted file mode 100644 index 8c8e52ac3a..0000000000 --- a/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/__tests__/__snapshots__/index.spec.ts.snap +++ /dev/null @@ -1,85 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`useWithdrawFromPendleVault > calls useSendTransaction with the correct parameters for withdraw 3`] = ` -[ - [ - { - "queryKey": [ - "GET_BALANCE_OF", - { - "accountAddress": "0x3d759121234cd36F8124C21aFe1c6852d2bEd848", - "chainId": 97, - "tokenAddress": "0xB9e0E753630434d7863528cc73CB7AC638a7c8ff", - }, - ], - }, - ], - [ - { - "queryKey": [ - "GET_TOKEN_ALLOWANCE", - { - "accountAddress": "0x3d759121234cd36F8124C21aFe1c6852d2bEd848", - "chainId": 97, - "spenderAddress": "0xa258a693A403b7e98fd05EE9e1558C760308cFC7", - "tokenAddress": "0xB9e0E753630434d7863528cc73CB7AC638a7c8ff", - }, - ], - }, - ], - [ - { - "queryKey": [ - "GET_BALANCE_OF", - { - "accountAddress": "0x3d759121234cd36F8124C21aFe1c6852d2bEd848", - "chainId": 97, - "tokenAddress": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", - }, - ], - }, - ], - [ - { - "queryKey": [ - "GET_TOKEN_BALANCES", - { - "accountAddress": "0x3d759121234cd36F8124C21aFe1c6852d2bEd848", - "chainId": 97, - }, - ], - }, - ], - [ - { - "queryKey": [ - "GET_FIXED_RATED_VAULTS", - { - "chainId": 97, - }, - ], - }, - ], - [ - { - "queryKey": [ - "GET_V_TOKEN_BALANCES_ALL", - ], - }, - ], - [ - { - "queryKey": [ - "GET_POOLS", - ], - }, - ], - [ - { - "queryKey": [ - "GET_FIXED_RATED_VAULTS", - ], - }, - ], -] -`; diff --git a/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/__tests__/index.spec.ts b/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/__tests__/index.spec.ts index cbc3baf51e..f99e3158aa 100644 --- a/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/__tests__/index.spec.ts +++ b/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/__tests__/index.spec.ts @@ -4,11 +4,13 @@ import fakeAccountAddress, { import BigNumber from 'bignumber.js'; import type { PendleContractWithdrawCallParams } from 'clients/api'; import { queryClient } from 'clients/api/queryClient'; +import FunctionKey from 'constants/functionKey'; import { useGetContractAddress } from 'hooks/useGetContractAddress'; import { useSendTransaction } from 'hooks/useSendTransaction'; import { useAnalytics } from 'libs/analytics'; import { renderHook } from 'testUtils/render'; import type { Mock } from 'vitest'; + import { useWithdrawFromPendleVault } from '..'; vi.mock('libs/contracts'); @@ -109,1796 +111,39 @@ describe('useWithdrawFromPendleVault', () => { const withdrawInput = { swapQuote: fakeWithdrawSwapQuote, - type: 'withdraw', fromToken: fakeFromToken, toToken: fakeToToken, amountMantissa: fakeAmountToken, vToken: fakeVToken, }; - expect(await fn(withdrawInput)).toMatchInlineSnapshot(` - { - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "pendleRouter_", - "type": "address", - }, - { - "internalType": "address", - "name": "comptroller_", - "type": "address", - }, - ], - "stateMutability": "nonpayable", - "type": "constructor", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "expected", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "received", - "type": "uint256", - }, - ], - "name": "InputAmountMismatch", - "type": "error", - }, - { - "inputs": [], - "name": "InvalidTokenInput", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maturity", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "currentTime", - "type": "uint256", - }, - ], - "name": "MarketAlreadyMatured", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - ], - "name": "MarketAlreadyRegistered", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maturity", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "currentTime", - "type": "uint256", - }, - ], - "name": "MarketNotMatured", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - ], - "name": "MarketNotRegistered", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address", - }, - { - "internalType": "address", - "name": "calledContract", - "type": "address", - }, - { - "internalType": "string", - "name": "methodSignature", - "type": "string", - }, - ], - "name": "Unauthorized", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vToken", - "type": "address", - }, - { - "internalType": "address", - "name": "expectedUnderlying", - "type": "address", - }, - ], - "name": "UnderlyingMismatch", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "errorCode", - "type": "uint256", - }, - ], - "name": "VTokenMintFailed", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vToken", - "type": "address", - }, - ], - "name": "VTokenNotListed", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "errorCode", - "type": "uint256", - }, - ], - "name": "VTokenRedeemFailed", - "type": "error", - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error", - }, - { - "inputs": [], - "name": "ZeroAmount", - "type": "error", - }, - { - "inputs": [], - "name": "ZeroVTokensMinted", - "type": "error", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "tokenIn", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amountIn", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "ptAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - ], - "name": "Deposited", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8", - }, - ], - "name": "Initialized", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "pt", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "vToken", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "maturity", - "type": "uint256", - }, - ], - "name": "MarketAdded", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldAccessControlManager", - "type": "address", - }, - { - "indexed": false, - "internalType": "address", - "name": "newAccessControlManager", - "type": "address", - }, - ], - "name": "NewAccessControlManager", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address", - }, - ], - "name": "OwnershipTransferStarted", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address", - }, - ], - "name": "OwnershipTransferred", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address", - }, - ], - "name": "Paused", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "tokenOut", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "ptAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amountOut", - "type": "uint256", - }, - ], - "name": "RedeemedAtMaturity", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256", - }, - ], - "name": "SweepNative", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256", - }, - ], - "name": "SweepTokens", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address", - }, - ], - "name": "Unpaused", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "tokenOut", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "ptAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amountOut", - "type": "uint256", - }, - ], - "name": "Withdrawn", - "type": "event", - }, - { - "inputs": [], - "name": "COMPTROLLER", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "PENDLE_ROUTER", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "acceptOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "accessControlManager", - "outputs": [ - { - "internalType": "contract IAccessControlManagerV8", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "address", - "name": "vToken", - "type": "address", - }, - ], - "name": "addMarket", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "uint256", - "name": "minPtOut", - "type": "uint256", - }, - { - "components": [ - { - "internalType": "uint256", - "name": "guessMin", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "guessMax", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "guessOffchain", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "maxIteration", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "eps", - "type": "uint256", - }, - ], - "internalType": "struct ApproxParams", - "name": "guessPtOut", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "tokenIn", - "type": "address", - }, - { - "internalType": "uint256", - "name": "netTokenIn", - "type": "uint256", - }, - { - "internalType": "address", - "name": "tokenMintSy", - "type": "address", - }, - { - "internalType": "address", - "name": "pendleSwap", - "type": "address", - }, - { - "components": [ - { - "internalType": "enum SwapType", - "name": "swapType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "extRouter", - "type": "address", - }, - { - "internalType": "bytes", - "name": "extCalldata", - "type": "bytes", - }, - { - "internalType": "bool", - "name": "needScale", - "type": "bool", - }, - ], - "internalType": "struct SwapData", - "name": "swapData", - "type": "tuple", - }, - ], - "internalType": "struct TokenInput", - "name": "input", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "limitRouter", - "type": "address", - }, - { - "internalType": "uint256", - "name": "epsSkipMarket", - "type": "uint256", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "normalFills", - "type": "tuple[]", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "flashFills", - "type": "tuple[]", - }, - { - "internalType": "bytes", - "name": "optData", - "type": "bytes", - }, - ], - "internalType": "struct LimitOrderData", - "name": "limit", - "type": "tuple", - }, - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "netVTokensMinted", - "type": "uint256", - }, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "uint256", - "name": "minPtOut", - "type": "uint256", - }, - { - "components": [ - { - "internalType": "uint256", - "name": "guessMin", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "guessMax", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "guessOffchain", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "maxIteration", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "eps", - "type": "uint256", - }, - ], - "internalType": "struct ApproxParams", - "name": "guessPtOut", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "tokenIn", - "type": "address", - }, - { - "internalType": "uint256", - "name": "netTokenIn", - "type": "uint256", - }, - { - "internalType": "address", - "name": "tokenMintSy", - "type": "address", - }, - { - "internalType": "address", - "name": "pendleSwap", - "type": "address", - }, - { - "components": [ - { - "internalType": "enum SwapType", - "name": "swapType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "extRouter", - "type": "address", - }, - { - "internalType": "bytes", - "name": "extCalldata", - "type": "bytes", - }, - { - "internalType": "bool", - "name": "needScale", - "type": "bool", - }, - ], - "internalType": "struct SwapData", - "name": "swapData", - "type": "tuple", - }, - ], - "internalType": "struct TokenInput", - "name": "input", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "limitRouter", - "type": "address", - }, - { - "internalType": "uint256", - "name": "epsSkipMarket", - "type": "uint256", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "normalFills", - "type": "tuple[]", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "flashFills", - "type": "tuple[]", - }, - { - "internalType": "bytes", - "name": "optData", - "type": "bytes", - }, - ], - "internalType": "struct LimitOrderData", - "name": "limit", - "type": "tuple", - }, - ], - "name": "depositNative", - "outputs": [ - { - "internalType": "uint256", - "name": "netVTokensMinted", - "type": "uint256", - }, - ], - "stateMutability": "payable", - "type": "function", - }, - { - "inputs": [], - "name": "getAllMarkets", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "getMarketCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "accessControlManager_", - "type": "address", - }, - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address", - }, - ], - "name": "isDelegated", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - ], - "name": "isMatured", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256", - }, - ], - "name": "marketList", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "name": "markets", - "outputs": [ - { - "internalType": "address", - "name": "pt", - "type": "address", - }, - { - "internalType": "address", - "name": "sy", - "type": "address", - }, - { - "internalType": "address", - "name": "yt", - "type": "address", - }, - { - "internalType": "address", - "name": "vToken", - "type": "address", - }, - { - "internalType": "uint256", - "name": "maturity", - "type": "uint256", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "pendingOwner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - { - "components": [ - { - "internalType": "address", - "name": "tokenOut", - "type": "address", - }, - { - "internalType": "uint256", - "name": "minTokenOut", - "type": "uint256", - }, - { - "internalType": "address", - "name": "tokenRedeemSy", - "type": "address", - }, - { - "internalType": "address", - "name": "pendleSwap", - "type": "address", - }, - { - "components": [ - { - "internalType": "enum SwapType", - "name": "swapType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "extRouter", - "type": "address", - }, - { - "internalType": "bytes", - "name": "extCalldata", - "type": "bytes", - }, - { - "internalType": "bool", - "name": "needScale", - "type": "bool", - }, - ], - "internalType": "struct SwapData", - "name": "swapData", - "type": "tuple", - }, - ], - "internalType": "struct TokenOutput", - "name": "output", - "type": "tuple", - }, - ], - "name": "redeemAtMaturity", - "outputs": [ - { - "internalType": "uint256", - "name": "netTokenOut", - "type": "uint256", - }, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "accessControlManager_", - "type": "address", - }, - ], - "name": "setAccessControlManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address payable", - "name": "to", - "type": "address", - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256", - }, - ], - "name": "sweepNative", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "to", - "type": "address", - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256", - }, - ], - "name": "sweepTokens", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address", - }, - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - { - "components": [ - { - "internalType": "address", - "name": "tokenOut", - "type": "address", - }, - { - "internalType": "uint256", - "name": "minTokenOut", - "type": "uint256", - }, - { - "internalType": "address", - "name": "tokenRedeemSy", - "type": "address", - }, - { - "internalType": "address", - "name": "pendleSwap", - "type": "address", - }, - { - "components": [ - { - "internalType": "enum SwapType", - "name": "swapType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "extRouter", - "type": "address", - }, - { - "internalType": "bytes", - "name": "extCalldata", - "type": "bytes", - }, - { - "internalType": "bool", - "name": "needScale", - "type": "bool", - }, - ], - "internalType": "struct SwapData", - "name": "swapData", - "type": "tuple", - }, - ], - "internalType": "struct TokenOutput", - "name": "output", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "limitRouter", - "type": "address", - }, - { - "internalType": "uint256", - "name": "epsSkipMarket", - "type": "uint256", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "normalFills", - "type": "tuple[]", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "flashFills", - "type": "tuple[]", - }, - { - "internalType": "bytes", - "name": "optData", - "type": "bytes", - }, - ], - "internalType": "struct LimitOrderData", - "name": "limit", - "type": "tuple", - }, - ], - "name": "withdraw", - "outputs": [ - { - "internalType": "uint256", - "name": "netTokenOut", - "type": "uint256", - }, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "stateMutability": "payable", - "type": "receive", - }, - ], - "address": "0xfakePendlePtVaultContractAddress", - "args": [ - "0x3c1a3d6b69a866444fe506f7d38a00a1c2d859c5", - 99877n, - { - "minTokenOut": 1000000000000000n, - "pendleSwap": "0x0000000000000000000000000000000000000000", - "swapData": { - "extCalldata": "0x", - "extRouter": "0x0000000000000000000000000000000000000000", - "needScale": false, - "swapType": 0, - }, - "tokenOut": "0x0000000000000000000000000000000000000000", - "tokenRedeemSy": "0x0000000000000000000000000000000000000000", - }, - { - "epsSkipMarket": 0n, - "flashFills": [], - "limitRouter": "0x0000000000000000000000000000000000000000", - "normalFills": [], - "optData": "0x", - }, - ], - "functionName": "withdraw", - } - `); + expect(fn(withdrawInput)).toMatchObject({ + address: '0xfakePendlePtVaultContractAddress', + functionName: 'withdraw', + args: [ + '0x3c1a3d6b69a866444fe506f7d38a00a1c2d859c5', + 99877n, + { + minTokenOut: 1000000000000000n, + pendleSwap: '0x0000000000000000000000000000000000000000', + swapData: { + extCalldata: '0x', + extRouter: '0x0000000000000000000000000000000000000000', + needScale: false, + swapType: 0, + }, + tokenOut: '0x0000000000000000000000000000000000000000', + tokenRedeemSy: '0x0000000000000000000000000000000000000000', + }, + { + epsSkipMarket: 0n, + flashFills: [], + limitRouter: '0x0000000000000000000000000000000000000000', + normalFills: [], + optData: '0x', + }, + ], + }); await onConfirmed({ input: withdrawInput }); @@ -1917,1816 +162,12 @@ describe('useWithdrawFromPendleVault', () => { ] `); - expect((queryClient.invalidateQueries as Mock).mock.calls).toMatchSnapshot(); - }); - - it('calls useSendTransaction with the correct parameters for redeemAtMaturity', async () => { - renderHook( - () => - useWithdrawFromPendleVault( - { - pendleMarketAddress: fakePendleMarketAddress, - poolComptrollerAddress: fakePoolComptrollerAddress, - }, - fakeOptions, - ), - { accountAddress: fakeAccountAddress }, - ); - - const { fn } = (useSendTransaction as Mock).mock.calls[0][0]; - - const redeemInput = { - swapQuote: fakeWithdrawSwapQuote, - type: 'redeemAtMaturity', - fromToken: fakeFromToken, - toToken: fakeToToken, - amountMantissa: fakeAmountToken, - vToken: fakeVToken, - }; - - expect(await fn(redeemInput)).toMatchInlineSnapshot(` - { - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "pendleRouter_", - "type": "address", - }, - { - "internalType": "address", - "name": "comptroller_", - "type": "address", - }, - ], - "stateMutability": "nonpayable", - "type": "constructor", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "expected", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "received", - "type": "uint256", - }, - ], - "name": "InputAmountMismatch", - "type": "error", - }, - { - "inputs": [], - "name": "InvalidTokenInput", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maturity", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "currentTime", - "type": "uint256", - }, - ], - "name": "MarketAlreadyMatured", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - ], - "name": "MarketAlreadyRegistered", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maturity", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "currentTime", - "type": "uint256", - }, - ], - "name": "MarketNotMatured", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - ], - "name": "MarketNotRegistered", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address", - }, - { - "internalType": "address", - "name": "calledContract", - "type": "address", - }, - { - "internalType": "string", - "name": "methodSignature", - "type": "string", - }, - ], - "name": "Unauthorized", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vToken", - "type": "address", - }, - { - "internalType": "address", - "name": "expectedUnderlying", - "type": "address", - }, - ], - "name": "UnderlyingMismatch", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "errorCode", - "type": "uint256", - }, - ], - "name": "VTokenMintFailed", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vToken", - "type": "address", - }, - ], - "name": "VTokenNotListed", - "type": "error", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "errorCode", - "type": "uint256", - }, - ], - "name": "VTokenRedeemFailed", - "type": "error", - }, - { - "inputs": [], - "name": "ZeroAddress", - "type": "error", - }, - { - "inputs": [], - "name": "ZeroAmount", - "type": "error", - }, - { - "inputs": [], - "name": "ZeroVTokensMinted", - "type": "error", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "tokenIn", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amountIn", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "ptAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - ], - "name": "Deposited", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8", - }, - ], - "name": "Initialized", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "pt", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "vToken", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "maturity", - "type": "uint256", - }, - ], - "name": "MarketAdded", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldAccessControlManager", - "type": "address", - }, - { - "indexed": false, - "internalType": "address", - "name": "newAccessControlManager", - "type": "address", - }, - ], - "name": "NewAccessControlManager", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address", - }, - ], - "name": "OwnershipTransferStarted", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address", - }, - ], - "name": "OwnershipTransferred", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address", - }, - ], - "name": "Paused", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "tokenOut", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "ptAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amountOut", - "type": "uint256", - }, - ], - "name": "RedeemedAtMaturity", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256", - }, - ], - "name": "SweepNative", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256", - }, - ], - "name": "SweepTokens", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address", - }, - ], - "name": "Unpaused", - "type": "event", - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address", - }, - { - "indexed": true, - "internalType": "address", - "name": "tokenOut", - "type": "address", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "ptAmount", - "type": "uint256", - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amountOut", - "type": "uint256", - }, - ], - "name": "Withdrawn", - "type": "event", - }, - { - "inputs": [], - "name": "COMPTROLLER", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "PENDLE_ROUTER", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "acceptOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "accessControlManager", - "outputs": [ - { - "internalType": "contract IAccessControlManagerV8", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "address", - "name": "vToken", - "type": "address", - }, - ], - "name": "addMarket", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "uint256", - "name": "minPtOut", - "type": "uint256", - }, - { - "components": [ - { - "internalType": "uint256", - "name": "guessMin", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "guessMax", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "guessOffchain", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "maxIteration", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "eps", - "type": "uint256", - }, - ], - "internalType": "struct ApproxParams", - "name": "guessPtOut", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "tokenIn", - "type": "address", - }, - { - "internalType": "uint256", - "name": "netTokenIn", - "type": "uint256", - }, - { - "internalType": "address", - "name": "tokenMintSy", - "type": "address", - }, - { - "internalType": "address", - "name": "pendleSwap", - "type": "address", - }, - { - "components": [ - { - "internalType": "enum SwapType", - "name": "swapType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "extRouter", - "type": "address", - }, - { - "internalType": "bytes", - "name": "extCalldata", - "type": "bytes", - }, - { - "internalType": "bool", - "name": "needScale", - "type": "bool", - }, - ], - "internalType": "struct SwapData", - "name": "swapData", - "type": "tuple", - }, - ], - "internalType": "struct TokenInput", - "name": "input", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "limitRouter", - "type": "address", - }, - { - "internalType": "uint256", - "name": "epsSkipMarket", - "type": "uint256", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "normalFills", - "type": "tuple[]", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "flashFills", - "type": "tuple[]", - }, - { - "internalType": "bytes", - "name": "optData", - "type": "bytes", - }, - ], - "internalType": "struct LimitOrderData", - "name": "limit", - "type": "tuple", - }, - ], - "name": "deposit", - "outputs": [ - { - "internalType": "uint256", - "name": "netVTokensMinted", - "type": "uint256", - }, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "uint256", - "name": "minPtOut", - "type": "uint256", - }, - { - "components": [ - { - "internalType": "uint256", - "name": "guessMin", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "guessMax", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "guessOffchain", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "maxIteration", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "eps", - "type": "uint256", - }, - ], - "internalType": "struct ApproxParams", - "name": "guessPtOut", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "tokenIn", - "type": "address", - }, - { - "internalType": "uint256", - "name": "netTokenIn", - "type": "uint256", - }, - { - "internalType": "address", - "name": "tokenMintSy", - "type": "address", - }, - { - "internalType": "address", - "name": "pendleSwap", - "type": "address", - }, - { - "components": [ - { - "internalType": "enum SwapType", - "name": "swapType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "extRouter", - "type": "address", - }, - { - "internalType": "bytes", - "name": "extCalldata", - "type": "bytes", - }, - { - "internalType": "bool", - "name": "needScale", - "type": "bool", - }, - ], - "internalType": "struct SwapData", - "name": "swapData", - "type": "tuple", - }, - ], - "internalType": "struct TokenInput", - "name": "input", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "limitRouter", - "type": "address", - }, - { - "internalType": "uint256", - "name": "epsSkipMarket", - "type": "uint256", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "normalFills", - "type": "tuple[]", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "flashFills", - "type": "tuple[]", - }, - { - "internalType": "bytes", - "name": "optData", - "type": "bytes", - }, - ], - "internalType": "struct LimitOrderData", - "name": "limit", - "type": "tuple", - }, - ], - "name": "depositNative", - "outputs": [ - { - "internalType": "uint256", - "name": "netVTokensMinted", - "type": "uint256", - }, - ], - "stateMutability": "payable", - "type": "function", - }, - { - "inputs": [], - "name": "getAllMarkets", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "getMarketCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "accessControlManager_", - "type": "address", - }, - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address", - }, - ], - "name": "isDelegated", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - ], - "name": "isMatured", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256", - }, - ], - "name": "marketList", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "name": "markets", - "outputs": [ - { - "internalType": "address", - "name": "pt", - "type": "address", - }, - { - "internalType": "address", - "name": "sy", - "type": "address", - }, - { - "internalType": "address", - "name": "yt", - "type": "address", - }, - { - "internalType": "address", - "name": "vToken", - "type": "address", - }, - { - "internalType": "uint256", - "name": "maturity", - "type": "uint256", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "pendingOwner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address", - }, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - { - "components": [ - { - "internalType": "address", - "name": "tokenOut", - "type": "address", - }, - { - "internalType": "uint256", - "name": "minTokenOut", - "type": "uint256", - }, - { - "internalType": "address", - "name": "tokenRedeemSy", - "type": "address", - }, - { - "internalType": "address", - "name": "pendleSwap", - "type": "address", - }, - { - "components": [ - { - "internalType": "enum SwapType", - "name": "swapType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "extRouter", - "type": "address", - }, - { - "internalType": "bytes", - "name": "extCalldata", - "type": "bytes", - }, - { - "internalType": "bool", - "name": "needScale", - "type": "bool", - }, - ], - "internalType": "struct SwapData", - "name": "swapData", - "type": "tuple", - }, - ], - "internalType": "struct TokenOutput", - "name": "output", - "type": "tuple", - }, - ], - "name": "redeemAtMaturity", - "outputs": [ - { - "internalType": "uint256", - "name": "netTokenOut", - "type": "uint256", - }, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "accessControlManager_", - "type": "address", - }, - ], - "name": "setAccessControlManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address payable", - "name": "to", - "type": "address", - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256", - }, - ], - "name": "sweepNative", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "to", - "type": "address", - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256", - }, - ], - "name": "sweepTokens", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address", - }, - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pendleMarket", - "type": "address", - }, - { - "internalType": "uint256", - "name": "vTokenAmount", - "type": "uint256", - }, - { - "components": [ - { - "internalType": "address", - "name": "tokenOut", - "type": "address", - }, - { - "internalType": "uint256", - "name": "minTokenOut", - "type": "uint256", - }, - { - "internalType": "address", - "name": "tokenRedeemSy", - "type": "address", - }, - { - "internalType": "address", - "name": "pendleSwap", - "type": "address", - }, - { - "components": [ - { - "internalType": "enum SwapType", - "name": "swapType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "extRouter", - "type": "address", - }, - { - "internalType": "bytes", - "name": "extCalldata", - "type": "bytes", - }, - { - "internalType": "bool", - "name": "needScale", - "type": "bool", - }, - ], - "internalType": "struct SwapData", - "name": "swapData", - "type": "tuple", - }, - ], - "internalType": "struct TokenOutput", - "name": "output", - "type": "tuple", - }, - { - "components": [ - { - "internalType": "address", - "name": "limitRouter", - "type": "address", - }, - { - "internalType": "uint256", - "name": "epsSkipMarket", - "type": "uint256", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "normalFills", - "type": "tuple[]", - }, - { - "components": [ - { - "components": [ - { - "internalType": "uint256", - "name": "salt", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256", - }, - { - "internalType": "enum IPLimitOrderType.OrderType", - "name": "orderType", - "type": "uint8", - }, - { - "internalType": "address", - "name": "token", - "type": "address", - }, - { - "internalType": "address", - "name": "YT", - "type": "address", - }, - { - "internalType": "address", - "name": "maker", - "type": "address", - }, - { - "internalType": "address", - "name": "receiver", - "type": "address", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "lnImpliedRate", - "type": "uint256", - }, - { - "internalType": "uint256", - "name": "failSafeRate", - "type": "uint256", - }, - { - "internalType": "bytes", - "name": "permit", - "type": "bytes", - }, - ], - "internalType": "struct Order", - "name": "order", - "type": "tuple", - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes", - }, - { - "internalType": "uint256", - "name": "makingAmount", - "type": "uint256", - }, - ], - "internalType": "struct FillOrderParams[]", - "name": "flashFills", - "type": "tuple[]", - }, - { - "internalType": "bytes", - "name": "optData", - "type": "bytes", - }, - ], - "internalType": "struct LimitOrderData", - "name": "limit", - "type": "tuple", - }, - ], - "name": "withdraw", - "outputs": [ - { - "internalType": "uint256", - "name": "netTokenOut", - "type": "uint256", - }, - ], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "stateMutability": "payable", - "type": "receive", - }, - ], - "address": "0xfakePendlePtVaultContractAddress", - "args": [ - "0x3c1a3d6b69a866444fe506f7d38a00a1c2d859c5", - 99877n, - { - "minTokenOut": 1000000000000000n, - "pendleSwap": "0x0000000000000000000000000000000000000000", - "swapData": { - "extCalldata": "0x", - "extRouter": "0x0000000000000000000000000000000000000000", - "needScale": false, - "swapType": 0, - }, - "tokenOut": "0x0000000000000000000000000000000000000000", - "tokenRedeemSy": "0x0000000000000000000000000000000000000000", - }, - { - "epsSkipMarket": 0n, - "flashFills": [], - "limitRouter": "0x0000000000000000000000000000000000000000", - "normalFills": [], - "optData": "0x", - }, - ], - "functionName": "redeemAtMaturity", - } - `); + expect(queryClient.invalidateQueries).toHaveBeenCalledWith({ + queryKey: [FunctionKey.GET_POOLS], + }); + expect(queryClient.invalidateQueries).toHaveBeenCalledWith({ + queryKey: [FunctionKey.GET_FIXED_RATED_VAULTS], + }); }); it('throws when vToken is missing', async () => { @@ -3745,7 +186,6 @@ describe('useWithdrawFromPendleVault', () => { const invalidInput = { swapQuote: fakeWithdrawSwapQuote, - type: 'withdraw', fromToken: fakeFromToken, toToken: fakeToToken, amountMantissa: fakeAmountToken, @@ -3772,7 +212,6 @@ describe('useWithdrawFromPendleVault', () => { const withdrawInput = { swapQuote: fakeWithdrawSwapQuote, - type: 'withdraw', fromToken: fakeFromToken, toToken: fakeToToken, amountMantissa: fakeAmountToken, diff --git a/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/formatWithdrawParams/index.ts b/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/formatWithdrawParams/index.ts deleted file mode 100644 index c9dac5bfc2..0000000000 --- a/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/formatWithdrawParams/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -import BigNumber from 'bignumber.js'; -import type { PendleContractWithdrawCallParams } from 'clients/api'; -import type { PendleFillOrderParams } from 'clients/api/queries/getPendleSwapQuote/types'; -import type { Token, VToken } from 'types'; -import { convertMantissaToTokens, convertTokensToMantissa } from 'utilities'; - -const formatFillOrderParams = (fills: PendleFillOrderParams[]) => - fills.map(({ order, signature, makingAmount }) => ({ - order: { - ...order, - salt: BigInt(order.salt), - expiry: BigInt(order.expiry), - nonce: BigInt(order.nonce), - orderType: Number(order.orderType), - makingAmount: BigInt(order.makingAmount), - lnImpliedRate: BigInt(order.lnImpliedRate), - failSafeRate: BigInt(order.failSafeRate), - }, - signature, - makingAmount: BigInt(makingAmount), - })); - -export const formatWithdrawParams = ( - params: PendleContractWithdrawCallParams, - { fromToken, vToken }: { fromToken: Token; vToken: VToken }, -) => { - if (!Array.isArray(params)) return params; - - const [, pendleMarket, tokenAmount, input, limit] = params; - - // The API handles underlying Token transfer quote, but the SC requres vToken amount instead, so there will be a conversion between the two and this is intentional. - const amountTokens = convertMantissaToTokens({ - value: new BigNumber(tokenAmount), - token: fromToken, - }); - - const vTokenMantissa = convertTokensToMantissa({ - value: amountTokens, - token: vToken, - }); - - return [ - pendleMarket, - BigInt(vTokenMantissa.toFixed(0, 1)), - { - ...input, - minTokenOut: BigInt(input.minTokenOut), - swapData: { - ...input.swapData, - swapType: Number(input.swapData.swapType), - }, - }, - { - ...limit, - epsSkipMarket: BigInt(limit.epsSkipMarket), - normalFills: formatFillOrderParams(limit.normalFills), - flashFills: formatFillOrderParams(limit.flashFills), - }, - ] as const; -}; diff --git a/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/index.ts b/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/index.ts index 3c972db292..2aac39214b 100644 --- a/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/index.ts +++ b/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/index.ts @@ -1,3 +1,6 @@ +import BigNumber from 'bignumber.js'; +import type { Address } from 'viem'; + import type { PendleContractWithdrawCallParams } from 'clients/api'; import { DEFAULT_SLIPPAGE_TOLERANCE_PERCENTAGE } from 'constants/swap'; import { useGetContractAddress } from 'hooks/useGetContractAddress'; @@ -7,10 +10,9 @@ import { pendlePtVaultAbi } from 'libs/contracts'; import { VError } from 'libs/errors'; import { useAccountAddress, useChainId } from 'libs/wallet'; import { convertMantissaToTokens } from 'utilities/convertMantissaToTokens'; -import type { Address } from 'viem'; -import { invalidatePendleVaultCaches } from '../../../../utilities/invalidatePendleVaultCaches'; -import type { Options, TrimmedPendlePtVaultInput } from '../useStakeInPendleVault/types'; -import { formatWithdrawParams } from './formatWithdrawParams'; +import { convertTokensToMantissa } from 'utilities/convertTokensToMantissa'; +import { invalidatePendleVaultCaches } from 'utilities/invalidatePendleVaultCaches'; +import type { Options, PendlePtVaultWithdrawInput } from './types'; export const useWithdrawFromPendleVault = ( { @@ -31,7 +33,64 @@ export const useWithdrawFromPendleVault = ( }); return useSendTransaction({ - fn: ({ swapQuote, type, fromToken, vToken }: TrimmedPendlePtVaultInput) => { + fn: ({ swapQuote, fromToken, vToken }: PendlePtVaultWithdrawInput) => { + const formatFillOrderParams = (fills: PendleContractWithdrawCallParams[4]['normalFills']) => + fills.map(({ order, signature, makingAmount }) => ({ + order: { + ...order, + salt: BigInt(order.salt), + expiry: BigInt(order.expiry), + nonce: BigInt(order.nonce), + orderType: Number(order.orderType), + makingAmount: BigInt(order.makingAmount), + lnImpliedRate: BigInt(order.lnImpliedRate), + failSafeRate: BigInt(order.failSafeRate), + }, + signature, + makingAmount: BigInt(makingAmount), + })); + + const formatWithdrawParams = ({ + params, + fromToken: inputToken, + vToken: inputVToken, + }: { + params: PendleContractWithdrawCallParams; + fromToken: PendlePtVaultWithdrawInput['fromToken']; + vToken: NonNullable; + }) => { + const [, pendleMarket, tokenAmount, input, limit] = params; + + const amountTokens = convertMantissaToTokens({ + value: new BigNumber(tokenAmount), + token: inputToken, + }); + + const vTokenMantissa = convertTokensToMantissa({ + value: amountTokens, + token: inputVToken, + }); + + return [ + pendleMarket, + BigInt(vTokenMantissa.toFixed(0, 1)), + { + ...input, + minTokenOut: BigInt(input.minTokenOut), + swapData: { + ...input.swapData, + swapType: Number(input.swapData.swapType), + }, + }, + { + ...limit, + epsSkipMarket: BigInt(limit.epsSkipMarket), + normalFills: formatFillOrderParams(limit.normalFills), + flashFills: formatFillOrderParams(limit.flashFills), + }, + ] as const; + }; + if (!pendlePtVaultContractAddress) { throw new VError({ type: 'unexpected', @@ -39,30 +98,16 @@ export const useWithdrawFromPendleVault = ( }); } - if (type === 'withdraw' && vToken) { + if (vToken) { return { abi: pendlePtVaultAbi, address: pendlePtVaultContractAddress, functionName: 'withdraw' as const, - args: formatWithdrawParams( - swapQuote.contractCallParams as PendleContractWithdrawCallParams, - { - fromToken, - vToken, - }, - ), - } as const; - } - - if (type === 'redeemAtMaturity' && vToken) { - return { - abi: pendlePtVaultAbi, - address: pendlePtVaultContractAddress, - functionName: 'redeemAtMaturity' as const, - args: formatWithdrawParams( - swapQuote.contractCallParams as PendleContractWithdrawCallParams, - { fromToken, vToken }, - ), + args: formatWithdrawParams({ + params: swapQuote.contractCallParams as PendleContractWithdrawCallParams, + fromToken, + vToken, + }) as never, } as const; } @@ -72,7 +117,7 @@ export const useWithdrawFromPendleVault = ( }); }, onConfirmed: async ({ input }) => { - captureAnalyticEvent(`Pendle vault ${input.type}`, { + captureAnalyticEvent('Pendle vault withdraw', { pendleMarketAddress, fromTokenSymbol: input.fromToken.symbol, fromTokenAmountTokens: convertMantissaToTokens({ diff --git a/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/types.ts b/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/types.ts new file mode 100644 index 0000000000..640c23d6b7 --- /dev/null +++ b/apps/evm/src/clients/api/mutations/useWithdrawFromPendleVault/types.ts @@ -0,0 +1,24 @@ +import type BigNumber from 'bignumber.js'; +import type { GetPendleSwapQuoteOutput } from 'clients/api/queries/getPendleSwapQuote'; +import type { UseSendTransactionOptions } from 'hooks/useSendTransaction'; +import type { Token, VToken } from 'types'; + +export type PendlePtVaultWithdrawInput = Record & { + swapQuote: GetPendleSwapQuoteOutput; + fromToken: Token; + toToken: Token; + amountMantissa: BigNumber; + vToken?: VToken; +}; + +export type Options = UseSendTransactionOptions; + +export type PendlePtVaultWithdrawAtMaturityInput = Record & { + fromToken: Token; + toToken: Token; + amountMantissa: BigNumber; + vToken?: VToken; +}; + +export type WithdrawAtMaturityOptions = + UseSendTransactionOptions; diff --git a/apps/evm/src/containers/VaultCard/PendleVaultModal/PositionTab/Footer/PendleConvertDetails/index.tsx b/apps/evm/src/containers/VaultCard/PendleVaultModal/PositionTab/Footer/PendleConvertDetails/index.tsx index e4e34113f6..e590ed5522 100644 --- a/apps/evm/src/containers/VaultCard/PendleVaultModal/PositionTab/Footer/PendleConvertDetails/index.tsx +++ b/apps/evm/src/containers/VaultCard/PendleVaultModal/PositionTab/Footer/PendleConvertDetails/index.tsx @@ -1,15 +1,22 @@ import { cn } from '@venusprotocol/ui'; +import type BigNumber from 'bignumber.js'; import type { GetPendleSwapQuoteOutput } from 'clients/api'; import { Icon, LabeledInlineContent } from 'components'; import { PLACEHOLDER_KEY } from 'constants/placeholders'; import { useTranslation } from 'libs/translations'; import type { Token } from 'types'; -import { convertMantissaToTokens, formatCentsToReadableValue } from 'utilities'; +import { + convertMantissaToTokens, + formatCentsToReadableValue, + formatTokensToReadableValue, +} from 'utilities'; export interface ConvertDetailsProps { fromToken: Token; + isMatured: boolean; toToken: Token; + userStakedTokens?: BigNumber; slippagePercentage: number; swapQuote?: GetPendleSwapQuoteOutput; className?: string; @@ -17,7 +24,9 @@ export interface ConvertDetailsProps { export const PendleConvertDetails: React.FC = ({ fromToken, + isMatured, toToken, + userStakedTokens, slippagePercentage, swapQuote, className, @@ -49,6 +58,11 @@ export const PendleConvertDetails: React.FC = ({ })}` : PLACEHOLDER_KEY; + const readableReceived = formatTokensToReadableValue({ + value: userStakedTokens, + token: toToken, + }); + return (
= ({
- {readableFee} + {isMatured && ( + + {readableReceived} + + )} - - {readableMinReceived} - + {!isMatured && ( + <> + + {readableFee} + - - {readableEstimatedReceived} - + + {readableMinReceived} + + + + {readableEstimatedReceived} + + + )} ); }; diff --git a/apps/evm/src/containers/VaultCard/PendleVaultModal/PositionTab/Footer/__tests__/index.spec.tsx b/apps/evm/src/containers/VaultCard/PendleVaultModal/PositionTab/Footer/__tests__/index.spec.tsx index 6b63222887..70e473ebd5 100644 --- a/apps/evm/src/containers/VaultCard/PendleVaultModal/PositionTab/Footer/__tests__/index.spec.tsx +++ b/apps/evm/src/containers/VaultCard/PendleVaultModal/PositionTab/Footer/__tests__/index.spec.tsx @@ -140,11 +140,12 @@ describe('Footer', () => { expect(queryByText(en.vault.modals.convert)).not.toBeInTheDocument(); }); - it('does not render conversion details for redeem at maturity even when slippage is provided', () => { + it('renders the convert direction and received amount for redeem at maturity', () => { const { getByText, queryByText } = renderComponent(