Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
feature(walletkit-ui): userPreferences, loans and DeFiScanContext (#45)
Browse files Browse the repository at this point in the history
* feature(walletkit-ui): userPreferences, loans and DeFiScanContext

* feature(walletkit-ui): userPreferences, loans and DeFiScanContext
  • Loading branch information
thedoublejay authored Dec 19, 2022
1 parent 2aaa7f8 commit 4e13280
Show file tree
Hide file tree
Showing 12 changed files with 1,364 additions and 0 deletions.
98 changes: 98 additions & 0 deletions packages/walletkit-ui/src/contexts/DeFiScanContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { EnvironmentNetwork } from "@waveshq/walletkit-core";
import React, { createContext, useContext, useMemo } from "react";

import { useNetworkContext } from "./NetworkContext";

interface DeFiScanContextI {
getTransactionUrl: (txid: string, rawtx?: string) => string;
getBlocksUrl: (blockCount: number) => string;
getTokenUrl: (tokenId: number | string) => string;
getAddressUrl: (address: string) => string;
getVaultsUrl: (vaultId: string) => string;
getAuctionsUrl: (vaultId: string, index: number) => string;
getBlocksCountdownUrl: (blockCount: number) => string;
}

const DeFiScanContext = createContext<DeFiScanContextI>(undefined as any);
const baseDefiScanUrl = "https://defiscan.live";

export function useDeFiScanContext(): DeFiScanContextI {
return useContext(DeFiScanContext);
}

function getNetworkParams(network: EnvironmentNetwork): string {
switch (network) {
case EnvironmentNetwork.MainNet:
// no-op: network param not required for MainNet
return "";
case EnvironmentNetwork.TestNet:
return `?network=${EnvironmentNetwork.TestNet}`;

case EnvironmentNetwork.LocalPlayground:
case EnvironmentNetwork.RemotePlayground:
return `?network=${EnvironmentNetwork.RemotePlayground}`;
default:
return "";
}
}

export function getURLByNetwork(
path: string,
network: EnvironmentNetwork,
id: number | string
): string {
return `${baseDefiScanUrl}/${path}/${id}${getNetworkParams(network)}`;
}

export function getTxURLByNetwork(
network: EnvironmentNetwork,
txid: string,
rawtx?: string
): string {
let baseUrl = `${baseDefiScanUrl}/transactions/${txid}`;

baseUrl += getNetworkParams(network);

if (typeof rawtx === "string" && rawtx.length !== 0) {
if (network === EnvironmentNetwork.MainNet) {
baseUrl += `?rawtx=${rawtx}`;
} else {
baseUrl += `&rawtx=${rawtx}`;
}
}

return baseUrl;
}

export function DeFiScanProvider(
props: React.PropsWithChildren<any>
): JSX.Element | null {
const { network } = useNetworkContext();
const { children } = props;

const context: DeFiScanContextI = useMemo(
() => ({
getTransactionUrl: (txid: string, rawtx?: string): string =>
getTxURLByNetwork(network, txid, rawtx),
getBlocksUrl: (blockCount: number) =>
getURLByNetwork("blocks", network, blockCount),
getTokenUrl: (tokenId: number | string) =>
getURLByNetwork("tokens", network, tokenId),
getAddressUrl: (address: string) =>
getURLByNetwork("address", network, address),
getVaultsUrl: (vaultId: string) =>
getURLByNetwork("vaults", network, vaultId),
getAuctionsUrl: (vaultId: string, index: number) =>
getURLByNetwork(`vaults/${vaultId}/auctions`, network, index),
getBlocksCountdownUrl: (blockCount: number) =>
getURLByNetwork("blocks/countdown", network, blockCount),
}),
[network]
);

return (
<DeFiScanContext.Provider value={context}>
{children}
</DeFiScanContext.Provider>
);
}
1 change: 1 addition & 0 deletions packages/walletkit-ui/src/contexts/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./DeFiScanContext";
export * from "./LanguageProvider";
export * from "./NetworkContext";
export * from "./PlaygroundContext";
Expand Down
2 changes: 2 additions & 0 deletions packages/walletkit-ui/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./useCollateralizationRatio";
export * from "./useVaultStatus";
197 changes: 197 additions & 0 deletions packages/walletkit-ui/src/hooks/useCollateralizationRatio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/* eslint-disable @typescript-eslint/no-shadow */
import BigNumber from "bignumber.js";

import {
CollateralizationRatioProps,
CollateralizationRatioStats,
VaultStatus,
} from "../store/types/VaultStatus";

export function useCollateralRatioStats({
colRatio,
minColRatio,
totalLoanAmount,
totalCollateralValue,
}: CollateralizationRatioProps): CollateralizationRatioStats {
const atRiskThreshold = new BigNumber(minColRatio).multipliedBy(1.5);
const liquidatedThreshold = new BigNumber(minColRatio).multipliedBy(1.25);
const isInLiquidation =
totalLoanAmount.gt(0) && colRatio.isLessThan(liquidatedThreshold);
const isAtRisk =
totalLoanAmount.gt(0) && colRatio.isLessThan(atRiskThreshold);
return {
atRiskThreshold,
liquidatedThreshold,
isInLiquidation,
isAtRisk,
isHealthy: !isInLiquidation && !isAtRisk && totalLoanAmount.gt(0),
isReady:
!isInLiquidation &&
!isAtRisk &&
totalLoanAmount.eq(0) &&
totalCollateralValue !== undefined &&
totalCollateralValue.gt(0),
};
}

// export function useCollateralizationRatioColor(
// props: CollateralizationRatioProps
// ): ThemedProps {
// const style: ThemedProps = {};
// const stats = useCollateralRatioStats(props);

// if (stats.isInLiquidation) {
// style.light = tailwind("text-error-500");
// style.dark = tailwind("text-darkerror-500");
// } else if (stats.isAtRisk) {
// style.light = tailwind("text-warning-500");
// style.dark = tailwind("text-darkwarning-500");
// } else if (stats.isHealthy) {
// style.light = tailwind("text-success-500");
// style.dark = tailwind("text-darksuccess-500");
// }
// return style;
// }

// export function getVaultStatusColor(
// status: string,
// isLight: boolean,
// isText: boolean = false
// ): string {
// if (status === VaultStatus.NearLiquidation) {
// return isText ? "text-red-v2" : getColor("red-v2");
// } else if (status === VaultStatus.AtRisk) {
// return isText ? "text-orange-v2" : getColor("orange-v2");
// } else if (status === VaultStatus.Healthy || status === VaultStatus.Ready) {
// return isText ? "text-green-v2" : getColor("green-v2");
// }
// return isText
// ? isLight
// ? "text-mono-light-v2-500"
// : "text-mono-dark-v2-500"
// : getColor(isLight ? "mono-light-v2-300" : "mono-dark-v2-300");
// }

export function getVaultStatusText(status: string): string {
switch (status) {
case VaultStatus.Ready:
return "Ready";
case VaultStatus.Halted:
return "Halted";
default:
return "Empty";
}
}

export function useResultingCollateralizationRatioByCollateral({
collateralValue,
collateralRatio,
minCollateralRatio,
totalLoanAmount,
numOfColorBars = 6,
totalCollateralValueInUSD,
}: {
collateralValue: string;
collateralRatio: BigNumber;
minCollateralRatio: BigNumber;
totalLoanAmount: BigNumber;
totalCollateralValue?: BigNumber;
numOfColorBars?: number;
totalCollateralValueInUSD: BigNumber;
}): {
resultingColRatio: BigNumber;
displayedColorBars: number;
} {
const hasCollateralRatio =
!new BigNumber(collateralRatio).isNaN() &&
new BigNumber(collateralRatio).isPositive();
const resultingColRatio =
collateralValue === "" ||
!hasCollateralRatio ||
new BigNumber(collateralValue).isZero()
? new BigNumber(collateralRatio)
: totalCollateralValueInUSD.dividedBy(totalLoanAmount).multipliedBy(100);

const numOfColorBarPerStatus = numOfColorBars / 3; // (3): liquidation, at risk, healthy
const healthyThresholdRatio = 1.75;
const atRiskThresholdRatio = 1.5;
const liquidatedThresholdRatio = 1.25;
const atRiskThreshold = new BigNumber(minCollateralRatio).multipliedBy(
atRiskThresholdRatio
);
const liquidatedThreshold = new BigNumber(minCollateralRatio).multipliedBy(
liquidatedThresholdRatio
);

const isAtRisk =
totalLoanAmount.gt(0) && resultingColRatio.isLessThan(atRiskThreshold);
const isInLiquidation =
totalLoanAmount.gt(0) && resultingColRatio.isLessThan(liquidatedThreshold);
const isHealthy = !isInLiquidation && !isAtRisk && totalLoanAmount.gt(0);

const getRatio = (): number => {
if (isHealthy) {
return healthyThresholdRatio;
}
if (isAtRisk && !isInLiquidation) {
return atRiskThresholdRatio;
}
return liquidatedThresholdRatio;
};

const getColorBarsCount = (
numOfColorBarPerStatus: number,
minCollateralRatio: BigNumber,
resultingCollateralRatio: BigNumber,
thresholdRatio: number,
isHealthy: boolean
): number => {
let colorBarsCount = -1;
let index = 1;
while (colorBarsCount === -1 && index <= numOfColorBarPerStatus) {
const colorBarMaxAmount = minCollateralRatio.plus(
minCollateralRatio.multipliedBy(
new BigNumber(thresholdRatio)
.minus(1)
.dividedBy(isHealthy ? 1 : numOfColorBarPerStatus)
.times(index) // divide threshold to number of bars
)
);

if (resultingCollateralRatio.isLessThanOrEqualTo(colorBarMaxAmount)) {
colorBarsCount = index;
}

index += 1;
}

return colorBarsCount;
};

const colorBarsCount = getColorBarsCount(
numOfColorBarPerStatus,
minCollateralRatio,
resultingColRatio,
getRatio(),
isHealthy
);

let displayedColorBars = -1;

if (resultingColRatio.isLessThanOrEqualTo(0)) {
displayedColorBars = -1;
} else if (isHealthy && colorBarsCount > 0) {
displayedColorBars = colorBarsCount + numOfColorBarPerStatus * 2;
} else if (isHealthy && colorBarsCount === -1) {
displayedColorBars = numOfColorBars; // display full color bar
} else if (isAtRisk && !isInLiquidation) {
displayedColorBars = colorBarsCount + numOfColorBarPerStatus;
} else {
displayedColorBars = colorBarsCount;
}

return {
displayedColorBars,
resultingColRatio,
};
}
43 changes: 43 additions & 0 deletions packages/walletkit-ui/src/hooks/useVaultStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { LoanVaultState } from "@defichain/whale-api-client/dist/api/loan";
import BigNumber from "bignumber.js";

import { VaultHealthItem, VaultStatus } from "../store/types/VaultStatus";
import { useCollateralRatioStats } from "./useCollateralizationRatio";

export function useVaultStatus(
status: LoanVaultState | undefined,
collateralRatio: BigNumber,
minColRatio: BigNumber,
totalLoanAmount: BigNumber,
totalCollateralValue: BigNumber
): VaultHealthItem {
const colRatio = collateralRatio.gte(0) ? collateralRatio : new BigNumber(0);
const stats = useCollateralRatioStats({
colRatio,
minColRatio,
totalLoanAmount,
totalCollateralValue,
});
let vaultStatus: VaultStatus;
if (status === LoanVaultState.FROZEN) {
vaultStatus = VaultStatus.Halted;
} else if (status === LoanVaultState.UNKNOWN) {
vaultStatus = VaultStatus.Unknown;
} else if (status === LoanVaultState.IN_LIQUIDATION) {
vaultStatus = VaultStatus.Liquidated;
} else if (stats.isInLiquidation) {
vaultStatus = VaultStatus.NearLiquidation;
} else if (stats.isAtRisk) {
vaultStatus = VaultStatus.AtRisk;
} else if (stats.isHealthy) {
vaultStatus = VaultStatus.Healthy;
} else if (stats.isReady) {
vaultStatus = VaultStatus.Ready;
} else {
vaultStatus = VaultStatus.Empty;
}
return {
status: vaultStatus,
vaultStats: stats,
};
}
1 change: 1 addition & 0 deletions packages/walletkit-ui/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./contexts";
export * from "./hooks";
export * from "./store";
3 changes: 3 additions & 0 deletions packages/walletkit-ui/src/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export * from "./block";
export * from "./loans";
export * from "./ocean";
export * from "./transaction_queue";
export * from "./types";
export * from "./userPreferences";
export * from "./wallet";
export * from "./website";
Loading

0 comments on commit 4e13280

Please sign in to comment.