From 67f6e463df47b22a7b029d8d139cec45d4f7804e Mon Sep 17 00:00:00 2001 From: Georges KABBOUCHI Date: Sun, 5 Sep 2021 21:58:18 +0300 Subject: [PATCH] compound projected debt Position --- .../protocols/aave-v2/deposit-and-borrow.ts | 2 - .../protocols/compound/deposit-and-borrow.ts | 139 +++++++++++++++++- .../compound/payback-and-withdraw.ts | 121 +++++++++++++++ 3 files changed, 258 insertions(+), 4 deletions(-) diff --git a/core/strategies/protocols/aave-v2/deposit-and-borrow.ts b/core/strategies/protocols/aave-v2/deposit-and-borrow.ts index 8ede76d..c53db4d 100644 --- a/core/strategies/protocols/aave-v2/deposit-and-borrow.ts +++ b/core/strategies/protocols/aave-v2/deposit-and-borrow.ts @@ -125,8 +125,6 @@ export default defineStrategy({ ? initialStats : newStats; - console.log(stats); - let liquidationPrice = "0"; if (!toBN(stats.ethSupplied).isZero()) { liquidationPrice = BigNumber.max( diff --git a/core/strategies/protocols/compound/deposit-and-borrow.ts b/core/strategies/protocols/compound/deposit-and-borrow.ts index 4604676..12d9a89 100644 --- a/core/strategies/protocols/compound/deposit-and-borrow.ts +++ b/core/strategies/protocols/compound/deposit-and-borrow.ts @@ -72,6 +72,84 @@ export default defineStrategy({ defaults: ({ getTokenByKey, variables }) => ({ token: getTokenByKey?.(variables.debtTokenKey) }) + }), + defineStrategyComponent({ + type: StrategyComponentType.HEADING, + name: "Projected Debt Position" + }), + defineStrategyComponent({ + type: StrategyComponentType.STATUS, + name: "Status", + update: ({ position, component, components, toBN, tokenIdMapping }) => { + if ( + toBN(components[0].value).isZero() && + toBN(components[1].value).isZero() + ) { + return; + } + + if (!position) { + return; + } + + const newPositionData = changedPositionData(position, components, tokenIdMapping.tokenToId); + const stats = calculateStats(newPositionData); + + component.liquidation = BigNumber.max( + toBN(stats.totalMaxBorrowLimitInEth).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, + tokenIdMapping + }) => { + if (!position) { + return; + } + + const newPositionData = changedPositionData( + position, + components, + tokenIdMapping.tokenToId + ); + const initialStats = calculateStats(position.data); + const newStats = calculateStats(newPositionData); + + const stats = + toBN(components[0].value).isZero() && + toBN(components[1].value).isZero() + ? initialStats + : newStats; + + let liquidationPrice = "0"; + if (!toBN(stats.ethSupplied).isZero()) { + liquidationPrice = BigNumber.max( + toBN(stats.totalBorrowInEth) + .div(stats.totalMaxBorrowLimitInEth) + .times(position.ethPriceInUsd), + "0" + ).toFixed(); + } + + component.value = `${formatting.formatUsdMax( + liquidationPrice, + position.ethPriceInUsd + )} / ${formatting.formatUsd(position.ethPriceInUsd)}`; + } }) ], @@ -106,7 +184,6 @@ export default defineStrategy({ stats.ethSupplied = supply; } - stats.totalSupplyInEth = toBN(supply) .times(priceInEth) .plus(stats.totalSupplyInEth) @@ -150,7 +227,11 @@ export default defineStrategy({ } }, - spells: async ({ components: inputs, convertTokenAmountToWei, tokenIdMapping }) => { + spells: async ({ + components: inputs, + convertTokenAmountToWei, + tokenIdMapping + }) => { const { tokenToId } = tokenIdMapping; const collateralTokenId = tokenToId.compound[inputs[0].token.key]; @@ -180,3 +261,57 @@ export default defineStrategy({ ]; } }); + +const changedPositionData = (position, inputs, tokenToId) => { + return position.data.map(position => { + const changedPosition = { ...position }; + if (tokenToId.compound[inputs[1].token.key] === position.cTokenId) { + changedPosition.borrow = BigNumber.max( + new BigNumber(position.borrow).plus(inputs[1].value), + "0" + ).toFixed(); + } + + if (tokenToId.compound[inputs[0].token.key] === position.cTokenId) { + changedPosition.supply = BigNumber.max( + new BigNumber(position.supply).plus(inputs[0].value), + "0" + ).toFixed(); + } + + return changedPosition; + }); +}; + +const calculateStats = positionData => { + return positionData.reduce( + (stats, { key, supply, borrow, priceInEth, factor }) => { + if (key === "eth") { + stats.ethSupplied = supply; + } + + stats.totalSupplyInEth = new BigNumber(supply) + .times(priceInEth) + .plus(stats.totalSupplyInEth) + .toFixed(); + stats.totalBorrowInEth = new BigNumber(borrow) + .times(priceInEth) + .plus(stats.totalBorrowInEth) + .toFixed(); + + stats.totalMaxBorrowLimitInEth = new BigNumber(priceInEth) + .times(factor) + .times(supply) + .plus(stats.totalMaxBorrowLimitInEth) + .toFixed(); + + return stats; + }, + { + totalSupplyInEth: "0", + totalBorrowInEth: "0", + totalMaxBorrowLimitInEth: "0", + ethSupplied: "0" + } + ); +}; diff --git a/core/strategies/protocols/compound/payback-and-withdraw.ts b/core/strategies/protocols/compound/payback-and-withdraw.ts index 2f390e1..13a4d64 100644 --- a/core/strategies/protocols/compound/payback-and-withdraw.ts +++ b/core/strategies/protocols/compound/payback-and-withdraw.ts @@ -76,6 +76,73 @@ 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, tokenIdMapping }) => { + if ( + toBN(components[0].value).isZero() && + toBN(components[1].value).isZero() + ) { + return; + } + + if (!position) { + return; + } + + const newPositionData = changedPositionData(position, components, tokenIdMapping.tokenToId); + 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, tokenIdMapping }) => { + if (!position) { + return; + } + + const newPositionData = changedPositionData(position, components, tokenIdMapping.tokenToId); + const initialStats = calculateStats(position.data); + const newStats = calculateStats(newPositionData); + + const stats = + toBN(components[0].value).isZero() && + toBN(components[1].value).isZero() + ? initialStats + : newStats; + + let liquidationPrice = "0"; + if (!toBN(stats.ethSupplied).isZero()) { + liquidationPrice = BigNumber.max( + toBN(stats.totalBorrowInEth) + .div(stats.totalMaxBorrowLimitInEth) + .times(position.ethPriceInUsd), + "0" + ).toFixed(); + } + + component.value = `${formatting.formatUsdMax( + liquidationPrice, + position.ethPriceInUsd + )} / ${formatting.formatUsd(position.ethPriceInUsd)}`; + } }) ], @@ -184,3 +251,57 @@ export default defineStrategy({ ]; } }); + +const changedPositionData = (position, inputs, tokenToId) => { + return position.data.map(position => { + const changedPosition = { ...position }; + if (tokenToId.compound[inputs[0].token.key] === position.cTokenId) { + changedPosition.borrow = BigNumber.max( + new BigNumber(position.borrow).minus(inputs[0].value), + "0" + ).toFixed(); + } + + if (tokenToId.compound[inputs[1].token.key] === position.cTokenId) { + 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, priceInEth, factor }) => { + if (key === "eth") { + stats.ethSupplied = supply; + } + + stats.totalSupplyInEth = new BigNumber(supply) + .times(priceInEth) + .plus(stats.totalSupplyInEth) + .toFixed(); + stats.totalBorrowInEth = new BigNumber(borrow) + .times(priceInEth) + .plus(stats.totalBorrowInEth) + .toFixed(); + + stats.totalMaxBorrowLimitInEth = new BigNumber(priceInEth) + .times(factor) + .times(supply) + .plus(stats.totalMaxBorrowLimitInEth) + .toFixed(); + + return stats; + }, + { + totalSupplyInEth: "0", + totalBorrowInEth: "0", + totalMaxBorrowLimitInEth: "0", + ethSupplied: "0" + } + ); +};