From 22036d9b058a0364185f63aaad0ef2a72551df72 Mon Sep 17 00:00:00 2001 From: halaprix Date: Thu, 21 Mar 2024 12:28:15 +0100 Subject: [PATCH] chore: add max withdraw and max deposit validations --- packages/dma-library/package.json | 2 +- .../src/strategies/common/erc4626/deposit.ts | 17 +++++++------ .../validation/validate-max-deposit.ts | 24 +++++++++++++++++++ .../validation/validate-max-withdraw.ts | 24 +++++++++++++++++++ .../src/strategies/common/erc4626/withdraw.ts | 5 ++-- .../src/types/ajna/ajna-strategy.ts | 4 +++- .../src/types/common/erc4626-validation.ts | 15 ++++++++++++ .../src/types/common/erc4626-view.ts | 5 ++++ .../dma-library/src/views/common/erc4626.ts | 11 ++++++--- 9 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 packages/dma-library/src/strategies/common/erc4626/validation/validate-max-deposit.ts create mode 100644 packages/dma-library/src/strategies/common/erc4626/validation/validate-max-withdraw.ts create mode 100644 packages/dma-library/src/types/common/erc4626-validation.ts diff --git a/packages/dma-library/package.json b/packages/dma-library/package.json index 48ee13014..3019188b9 100644 --- a/packages/dma-library/package.json +++ b/packages/dma-library/package.json @@ -1,6 +1,6 @@ { "name": "@oasisdex/dma-library", - "version": "0.6.41", + "version": "0.6.42", "typings": "lib/index.d.ts", "types": "lib/index.d.ts", "main": "lib/index.js", diff --git a/packages/dma-library/src/strategies/common/erc4626/deposit.ts b/packages/dma-library/src/strategies/common/erc4626/deposit.ts index 4355697bc..b066edf66 100644 --- a/packages/dma-library/src/strategies/common/erc4626/deposit.ts +++ b/packages/dma-library/src/strategies/common/erc4626/deposit.ts @@ -13,6 +13,7 @@ import { Erc4626DepositPayload, Erc4626DepositStrategy, } from '../../../types/common' +import { validateMaxDeposit } from './validation/validate-max-deposit' export const deposit: Erc4626DepositStrategy = async (args, dependencies) => { const addresses = { tokens: { ...ADDRESSES[dependencies.network][SystemKeys.COMMON] } } @@ -67,18 +68,16 @@ export const deposit: Erc4626DepositStrategy = async (args, dependencies) => { }, dependencies.network, ) - - const targetPosition = position.deposit( - new BigNumber( - ethers.utils - .formatUnits(swapData.minToTokenAmount.toString(), args.depositTokenPrecision) - .toString(), - ), + const depositAmount = new BigNumber( + ethers.utils + .formatUnits(swapData.minToTokenAmount.toString(), args.depositTokenPrecision) + .toString(), ) + const targetPosition = position.deposit(depositAmount) const warnings = [] - const errors = [] + const errors = [...validateMaxDeposit(depositAmount, position)] return { simulation: { @@ -119,7 +118,7 @@ export const deposit: Erc4626DepositStrategy = async (args, dependencies) => { const warnings = [] - const errors = [] + const errors = [...validateMaxDeposit(args.amount, position)] return { simulation: { diff --git a/packages/dma-library/src/strategies/common/erc4626/validation/validate-max-deposit.ts b/packages/dma-library/src/strategies/common/erc4626/validation/validate-max-deposit.ts new file mode 100644 index 000000000..18ec36e5d --- /dev/null +++ b/packages/dma-library/src/strategies/common/erc4626/validation/validate-max-deposit.ts @@ -0,0 +1,24 @@ +import { formatCryptoBalance } from '@dma-common/utils/common' +import { Erc4626Position } from '@dma-library/types' +import { Erc4626StrategyError } from '@dma-library/types/common/erc4626-validation' +import { BigNumber } from 'bignumber.js' + +export function validateMaxDeposit( + depositAmount: BigNumber, + position: Erc4626Position, +): Erc4626StrategyError[] { + const maxDeposit = position.maxDeposit + + if (depositAmount.gt(maxDeposit)) { + return [ + { + name: 'deposit-more-than-possible', + data: { + amount: formatCryptoBalance(maxDeposit), + }, + }, + ] + } + + return [] +} diff --git a/packages/dma-library/src/strategies/common/erc4626/validation/validate-max-withdraw.ts b/packages/dma-library/src/strategies/common/erc4626/validation/validate-max-withdraw.ts new file mode 100644 index 000000000..f45116003 --- /dev/null +++ b/packages/dma-library/src/strategies/common/erc4626/validation/validate-max-withdraw.ts @@ -0,0 +1,24 @@ +import { formatCryptoBalance } from '@dma-common/utils/common' +import { Erc4626Position } from '@dma-library/types' +import { Erc4626StrategyError } from '@dma-library/types/common/erc4626-validation' +import { BigNumber } from 'bignumber.js' + +export function validateMaxWithdraw( + withdrawAmount: BigNumber, + position: Erc4626Position, +): Erc4626StrategyError[] { + const maxWithdraw = position.maxWithdrawal + + if (withdrawAmount.gt(maxWithdraw)) { + return [ + { + name: 'withdraw-more-than-available', + data: { + amount: formatCryptoBalance(maxWithdraw), + }, + }, + ] + } + + return [] +} diff --git a/packages/dma-library/src/strategies/common/erc4626/withdraw.ts b/packages/dma-library/src/strategies/common/erc4626/withdraw.ts index bd7fbeeda..f58080953 100644 --- a/packages/dma-library/src/strategies/common/erc4626/withdraw.ts +++ b/packages/dma-library/src/strategies/common/erc4626/withdraw.ts @@ -12,6 +12,7 @@ import { Erc4626WithdrawPayload, Erc4626WithdrawStrategy, } from '../../../types/common' +import { validateMaxWithdraw } from './validation/validate-max-withdraw' export const withdraw: Erc4626WithdrawStrategy = async (args, dependencies) => { const addresses = { tokens: { ...ADDRESSES[dependencies.network][SystemKeys.COMMON] } } @@ -83,7 +84,7 @@ export const withdraw: Erc4626WithdrawStrategy = async (args, dependencies) => { const warnings = [] - const errors = [] + const errors = [...validateMaxWithdraw(args.amount, position)] return { simulation: { @@ -125,7 +126,7 @@ export const withdraw: Erc4626WithdrawStrategy = async (args, dependencies) => { const warnings = [] - const errors = [] + const errors = [...validateMaxWithdraw(args.amount, position)] return { simulation: { diff --git a/packages/dma-library/src/types/ajna/ajna-strategy.ts b/packages/dma-library/src/types/ajna/ajna-strategy.ts index 2bf6aee25..d7d00726e 100644 --- a/packages/dma-library/src/types/ajna/ajna-strategy.ts +++ b/packages/dma-library/src/types/ajna/ajna-strategy.ts @@ -1,9 +1,11 @@ import { Strategy } from '@dma-library/types' import { AjnaError, AjnaNotice, AjnaSuccess, AjnaWarning } from '@dma-library/types/ajna' +import { Erc4626StrategyError } from '../common/erc4626-validation' + export type SummerStrategy = Strategy & { simulation: Strategy['simulation'] & { - errors: AjnaError[] + errors: AjnaError[] | Erc4626StrategyError[] warnings: AjnaWarning[] notices: AjnaNotice[] successes: AjnaSuccess[] diff --git a/packages/dma-library/src/types/common/erc4626-validation.ts b/packages/dma-library/src/types/common/erc4626-validation.ts new file mode 100644 index 000000000..1cff6f807 --- /dev/null +++ b/packages/dma-library/src/types/common/erc4626-validation.ts @@ -0,0 +1,15 @@ +export type Erc4626StrategyError = Erc4626MaxWithdrawalError | Erc4626MaxDepositError + +export type Erc4626MaxWithdrawalError = { + name: 'withdraw-more-than-available' + data: { + amount: string + } +} + +export type Erc4626MaxDepositError = { + name: 'deposit-more-than-possible' + data: { + amount: string + } +} diff --git a/packages/dma-library/src/types/common/erc4626-view.ts b/packages/dma-library/src/types/common/erc4626-view.ts index 74bb7da86..c96f45cf3 100644 --- a/packages/dma-library/src/types/common/erc4626-view.ts +++ b/packages/dma-library/src/types/common/erc4626-view.ts @@ -128,6 +128,7 @@ export interface IErc4626Position extends SupplyPosition { } tvl: BigNumber maxWithdrawal: BigNumber + maxDeposit: BigNumber allocations?: { token: string supply: BigNumber @@ -197,6 +198,7 @@ export class Erc4626Position implements IErc4626Position { }, public totalEarnings: { withFees: BigNumber; withoutFees: BigNumber }, public maxWithdrawal: BigNumber, + public maxDeposit: BigNumber, public tvl: BigNumber, public allocations?: { token: string @@ -284,6 +286,7 @@ export class Erc4626Position implements IErc4626Position { this.pnl, this.totalEarnings, this.maxWithdrawal.plus(quoteTokenAmount), + this.maxDeposit.minus(quoteTokenAmount), this.tvl, this.allocations, this.rewards, @@ -304,6 +307,7 @@ export class Erc4626Position implements IErc4626Position { this.pnl, this.totalEarnings, this.maxWithdrawal.minus(quoteTokenAmount), + this.maxDeposit.plus(quoteTokenAmount), this.tvl, this.allocations, this.rewards, @@ -324,6 +328,7 @@ export class Erc4626Position implements IErc4626Position { this.pnl, this.totalEarnings, ZERO, + this.maxDeposit, this.tvl, this.allocations, this.rewards, diff --git a/packages/dma-library/src/views/common/erc4626.ts b/packages/dma-library/src/views/common/erc4626.ts index 126763c3f..7cec5e143 100644 --- a/packages/dma-library/src/views/common/erc4626.ts +++ b/packages/dma-library/src/views/common/erc4626.ts @@ -32,13 +32,17 @@ export async function getErc4626Position( const positionParameters = subgraphResponse.positions[0] const vaultParametersFromSubgraph = subgraphResponse.vaults[0] - const [balance, maxWithdraw] = await Promise.all([ + const [balance, maxWithdraw, maxDeposit] = await Promise.all([ vaultContractInstance.balanceOf(proxyAddress), vaultContractInstance.maxWithdraw(proxyAddress), + vaultContractInstance.maxDeposit(proxyAddress), ]) const assets = await vaultContractInstance.convertToAssets(balance) const quoteTokenAmount = new BigNumber(ethers.utils.formatUnits(assets, precision).toString()) - const maxWithdrawal = new BigNumber(ethers.utils.formatUnits(maxWithdraw, precision).toString()) + const maxWithdrawalAmount = new BigNumber( + ethers.utils.formatUnits(maxWithdraw, precision).toString(), + ) + const maxDepositAmount = new BigNumber(ethers.utils.formatUnits(maxDeposit, precision).toString()) const vault = { address: vaultAddress, @@ -120,7 +124,8 @@ export async function getErc4626Position( netValue, pnl, totalEarnings, - maxWithdrawal, + maxWithdrawalAmount, + maxDepositAmount, tvl, allocations, rewards,