From 75cd0fdac9b323a5410b6f1645dede110f8e3415 Mon Sep 17 00:00:00 2001 From: Georges KABBOUCHI Date: Sun, 5 Sep 2021 18:28:08 +0300 Subject: [PATCH] Add status component --- .../context/strategy/SidebarStrategy.vue | 13 +- composables/useStrategy.ts | 67 +++--- core/strategies/helpers/index.ts | 7 +- core/strategies/helpers/strategy.ts | 17 +- .../protocols/aave-v2/payback-and-withdraw.ts | 193 ++++++++++++------ 5 files changed, 203 insertions(+), 94 deletions(-) diff --git a/components/sidebar/context/strategy/SidebarStrategy.vue b/components/sidebar/context/strategy/SidebarStrategy.vue index b34dffc..389a1fe 100644 --- a/components/sidebar/context/strategy/SidebarStrategy.vue +++ b/components/sidebar/context/strategy/SidebarStrategy.vue @@ -24,7 +24,11 @@
-
+
+ +
diff --git a/composables/useStrategy.ts b/composables/useStrategy.ts index a71a4b8..ff0ef4b 100644 --- a/composables/useStrategy.ts +++ b/composables/useStrategy.ts @@ -14,7 +14,11 @@ import { import { position as aaveV2Position } from "./protocols/useAaveV2Position"; import { position as compoundPosition } from "./protocols/useCompoundPosition"; import { vault as makerPosition } from "./protocols/useMakerdaoPosition"; -import { trove as liquityPosition, troveTypes, troveOverallDetails } from "./protocols/useLiquityPosition"; +import { + trove as liquityPosition, + troveTypes, + troveOverallDetails +} from "./protocols/useLiquityPosition"; import { useBalances } from "./useBalances"; import { useDSA } from "./useDSA"; import useEventBus from "./useEventBus"; @@ -71,33 +75,44 @@ export function useStrategy(defineStrategy: DefineStrategy) { pending.value = false; }; - watchEffect(() => { - let position = null; - let positionExtra = {} + watch( + () => [ + aaveV2Position, + makerPosition, + compoundPosition, + liquityPosition, + troveTypes, + troveOverallDetails + ], + () => { + let position = null; + let positionExtra = {}; - if (strategy.schema.protocol == StrategyProtocol.AAVE_V2) { - position = aaveV2Position.value; - } else if (strategy.schema.protocol == StrategyProtocol.MAKERDAO) { - position = makerPosition.value; - } else if (strategy.schema.protocol == StrategyProtocol.COMPOUND) { - position = compoundPosition.value; - } else if (strategy.schema.protocol == StrategyProtocol.LIQUITY) { - position = liquityPosition.value; - - positionExtra["troveTypes"] = troveTypes.value; - positionExtra["troveOverallDetails"] = troveOverallDetails.value; - } + if (strategy.schema.protocol == StrategyProtocol.AAVE_V2) { + position = aaveV2Position.value; + } else if (strategy.schema.protocol == StrategyProtocol.MAKERDAO) { + position = makerPosition.value; + } else if (strategy.schema.protocol == StrategyProtocol.COMPOUND) { + position = compoundPosition.value; + } else if (strategy.schema.protocol == StrategyProtocol.LIQUITY) { + position = liquityPosition.value; - strategy.setProps({ - convertTokenAmountToWei: valInt, - getTokenByKey, - toBN, - position, - positionExtra, - tokenIdMapping, - formatting, - }); - }); + positionExtra["troveTypes"] = troveTypes.value; + positionExtra["troveOverallDetails"] = troveOverallDetails.value; + } + + strategy.setProps({ + convertTokenAmountToWei: valInt, + getTokenByKey, + toBN, + position, + positionExtra, + tokenIdMapping, + formatting + }); + }, + { immediate: true } + ); watch(web3, () => strategy.setWeb3(web3.value), { immediate: true }); watch(dsa, () => strategy.setDSA(dsa.value), { immediate: true }); diff --git a/core/strategies/helpers/index.ts b/core/strategies/helpers/index.ts index a288f48..ee8c2fe 100644 --- a/core/strategies/helpers/index.ts +++ b/core/strategies/helpers/index.ts @@ -40,7 +40,8 @@ export enum StrategyComponentType { INPUT_WITH_TOKEN = "input-with-token", HEADING = "heading", - VALUE = "value" + VALUE = "value", + STATUS = "status", } export type StrategyComponentParameterMap = { @@ -52,6 +53,10 @@ export type StrategyComponentParameterMap = { [StrategyComponentType.HEADING]: {}; [StrategyComponentType.VALUE]: {}; + [StrategyComponentType.STATUS]: { + liquidation?: any, + status?: any, + }; }; export interface IStrategyComponent { diff --git a/core/strategies/helpers/strategy.ts b/core/strategies/helpers/strategy.ts index cc594f8..8ba043d 100644 --- a/core/strategies/helpers/strategy.ts +++ b/core/strategies/helpers/strategy.ts @@ -58,7 +58,7 @@ export class Strategy { component.defaulted = true; } - this.notifyListeners(); + this.notifyListeners("SET_PROPS"); } generateComponents(components) { @@ -86,7 +86,7 @@ export class Strategy { }); } - this.notifyListeners(); + this.notifyListeners("onInput"); }, onCustomInput: (values: object) => { this.components[idx] = Object.assign(this.components[idx], values); @@ -95,7 +95,7 @@ export class Strategy { ...this.getContext(), component: this.components[idx] }); - this.notifyListeners(); + this.notifyListeners("onCustomInput"); } }; @@ -164,16 +164,21 @@ export class Strategy { setWeb3(web3: Web3) { this.context.web3 = web3; - this.notifyListeners(); + this.notifyListeners("WEB3"); } setDSA(dsa: DSA) { this.context.dsa = dsa; - this.notifyListeners(); + this.notifyListeners("DSA"); } - async notifyListeners() { + async notifyListeners( from = "") { + + if(from && process.env.NODE_ENV === "development") { + console.log(`${from} updated`); + } + for (const listener of this.listeners) { await listener(this); } diff --git a/core/strategies/protocols/aave-v2/payback-and-withdraw.ts b/core/strategies/protocols/aave-v2/payback-and-withdraw.ts index fcb66a2..2f5e033 100644 --- a/core/strategies/protocols/aave-v2/payback-and-withdraw.ts +++ b/core/strategies/protocols/aave-v2/payback-and-withdraw.ts @@ -72,6 +72,72 @@ export default defineStrategy({ defaults: ({ getTokenByKey }) => ({ token: getTokenByKey?.("eth") }) + }), + defineStrategyComponent({ + type: StrategyComponentType.HEADING, + name: "Projected Debt Position" + }), + defineStrategyComponent({ + type: StrategyComponentType.STATUS, + name: "Status", + update: ({ position, component, components, toBN }) => { + if ( + toBN(components[0].value).isZero() && + toBN(components[1].value).isZero() + ) { + return; + } + + if (!position) { + return; + } + + const newPositionData = changedPositionData(position, components); + const stats = calculateStats(newPositionData); + + component.liquidation = BigNumber.max( + toBN(stats.totalMaxLiquidationLimitInEth).div(stats.totalSupplyInEth), + "0" + ).toFixed(); + component.status = BigNumber.max( + toBN(stats.totalBorrowInEth).div(stats.totalSupplyInEth), + "0" + ).toFixed(); + } + }), + defineStrategyComponent({ + type: StrategyComponentType.VALUE, + name: "LIQUIDATION PRICE (IN ETH)", + value: "-", + update: ({ position, component, components, toBN, formatting }) => { + if (!position) { + return; + } + + const newPositionData = changedPositionData(position, components); + const initialStats = calculateStats(position.data); + const newStats = calculateStats(newPositionData); + + const stats = + toBN(components[0].value).isZero() && + toBN(components[1].value).isZero() + ? initialStats + : newStats; + + const liquidationPrice = BigNumber.max( + toBN(stats.totalBorrowInEth) + .div(stats.totalMaxLiquidationLimitInEth) + .times(position.ethPriceInUsd), + "0" + ).toFixed(); + + console.log(liquidationPrice); + + component.value = `${formatting.formatUsdMax( + liquidationPrice, + position.ethPriceInUsd + )} / ${formatting.formatUsd(position.ethPriceInUsd)}`; + } }) ], @@ -80,66 +146,8 @@ export default defineStrategy({ return; } - const newPositionData = position.data.map(position => { - const changedPosition = { ...position }; - if (inputs[0].token.key === position.key) { - changedPosition.borrow = BigNumber.max( - toBN(position.borrow).minus(inputs[0].value), - "0" - ).toFixed(); - } - - if (inputs[1].token.key === position.key) { - changedPosition.supply = BigNumber.max( - toBN(position.supply).minus(inputs[1].value), - "0" - ).toFixed(); - } - - return changedPosition; - }); - - const stats = newPositionData.reduce( - ( - stats, - { key, supply, borrow, borrowStable, priceInEth, factor, liquidation } - ) => { - if (key === "eth") { - stats.ethSupplied = supply; - } - - const borrowTotal = toBN(borrow).plus(borrowStable); - - stats.totalSupplyInEth = toBN(supply) - .times(priceInEth) - .plus(stats.totalSupplyInEth) - .toFixed(); - stats.totalBorrowInEth = toBN(borrowTotal) - .times(priceInEth) - .plus(stats.totalBorrowInEth) - .toFixed(); - - stats.totalMaxBorrowLimitInEth = toBN(priceInEth) - .times(factor) - .times(supply) - .plus(stats.totalMaxBorrowLimitInEth) - .toFixed(); - - stats.totalMaxLiquidationLimitInEth = toBN(priceInEth) - .times(liquidation) - .times(supply) - .plus(stats.totalMaxLiquidationLimitInEth) - .toFixed(); - - return stats; - }, - { - totalSupplyInEth: "0", - totalBorrowInEth: "0", - totalMaxBorrowLimitInEth: "0", - totalMaxLiquidationLimitInEth: "0" - } - ); + const newPositionData = changedPositionData(position, inputs); + const stats = calculateStats(newPositionData); let maxLiquidation = "0"; @@ -186,3 +194,68 @@ export default defineStrategy({ ]; } }); + +const changedPositionData = (position, inputs) => { + return position.data.map(position => { + const changedPosition = { ...position }; + if (inputs[0].token.key === position.key) { + changedPosition.borrow = BigNumber.max( + new BigNumber(position.borrow).minus(inputs[0].value), + "0" + ).toFixed(); + } + + if (inputs[1].token.key === position.key) { + changedPosition.supply = BigNumber.max( + new BigNumber(position.supply).minus(inputs[1].value), + "0" + ).toFixed(); + } + + return changedPosition; + }); +}; + +const calculateStats = positionData => { + return positionData.reduce( + ( + stats, + { key, supply, borrow, borrowStable, priceInEth, factor, liquidation } + ) => { + if (key === "eth") { + stats.ethSupplied = supply; + } + + const borrowTotal = new BigNumber(borrow).plus(borrowStable); + + stats.totalSupplyInEth = new BigNumber(supply) + .times(priceInEth) + .plus(stats.totalSupplyInEth) + .toFixed(); + stats.totalBorrowInEth = new BigNumber(borrowTotal) + .times(priceInEth) + .plus(stats.totalBorrowInEth) + .toFixed(); + + stats.totalMaxBorrowLimitInEth = new BigNumber(priceInEth) + .times(factor) + .times(supply) + .plus(stats.totalMaxBorrowLimitInEth) + .toFixed(); + + stats.totalMaxLiquidationLimitInEth = new BigNumber(priceInEth) + .times(liquidation) + .times(supply) + .plus(stats.totalMaxLiquidationLimitInEth) + .toFixed(); + + return stats; + }, + { + totalSupplyInEth: "0", + totalBorrowInEth: "0", + totalMaxBorrowLimitInEth: "0", + totalMaxLiquidationLimitInEth: "0" + } + ); +};