const StyledBox = styled.div` border-radius: 0px 0px 16px 16px; background: #2e3142; height: 0px; animation: fadeOut 0.4s 0.1s ease both; &.expand { animation: fadeIn 0.4s 0.1s ease both; } @keyframes fadeIn { 0% { opacity: 0; transform: translateY(-20px); height: 0px; border: none; } 100% { opacity: 1; transform: translateY(0); height: 300px; border: 1px solid #373a53; border-top: none; } } @keyframes fadeOut { 0% { opacity: 1; transform: translateY(0); height: 300px; border: 1px solid #373a53; border-top: none; } 100% { opacity: 0; transform: translateY(-20px); height: 0px; border: none; } } `; const StyledWrapper = styled.div` display: none; &.expand { display: block; } `; const StyledHeader = styled.div` height: 50px; border-bottom: 1px solid #373a53; `; const StyledTabs = styled.div` display: flex; align-items: center; justify-content: center; `; const StyledTab = styled.div` width: 250px; height: 50px; border-bottom: 5px solid transparent; color: #979abe; text-align: center; font-family: Gantari; font-size: 16px; font-style: normal; font-weight: 400; line-height: 50px; cursor: pointer; position: relative; transition: 0.3s; border-right: 1px solid #373a53; &:last-child { border-right: none; } &.active { border-bottom-color: #fff; color: #ffffff; } `; const StyledContent = styled.div` display: flex; justify-content: center; gap: 16px; padding-top: 16px; .disabled { opacity: 0.2; pointer-events: none; } `; const StyledInfo = styled.div` width: 520px; display: flex; justify-content: center; padding-bottom: 16px; `; const StyledInfoContent = styled.div` width: 390px; .icon { width: 16px; margin: 0 4px; } `; const StyledInfoTitle = styled.div` display: flex; align-items: center; color: #fff; font-family: Gantari; font-size: 16px; font-style: normal; font-weight: 400; line-height: normal; padding-bottom: 16px; .icon { width: 16px; margin: 0 4px; } `; const StyledInfoItem = styled.div` display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; color: #979abe; font-family: Gantari; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; & .white { color: #fff; } .symbol { margin-left: 4px; } .right { display: flex; align-items: center; } `; const StyledInfoTips = styled.div` width: 390px; height: 52px; display: flex; align-items: center; padding: 0 10px; background-color: rgba(235, 244, 121, 0.1); border-radius: 12px; gap: 8px; color: #ebf479; font-family: Gantari; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; margin-top: 10px; .text { display: flex; align-items: center; } .icon { width: 16px; margin-left: 4px; } `; const StyledDetailPanel = styled.div` width: 500px; padding: 12px; box-sizing: border-box; border-radius: 12px; border: 1px solid #373a53; color: #979abe; font-family: Gantari; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; display: flex; flex-direction: column; gap: 10px; margin-top: 12px; & .white { color: #fff; } `; const StyledDetailItem = styled.div` display: flex; justify-content: space-between; align-items: center; `; const StyledBorrowLimit = styled.div` display: flex; align-items: center; gap: 12px; `; const StyledButtonWrapper = styled.div` display: flex; align-items: center; gap: 22px; margin-top: 12px; height: 46px; `; const InfoWrap = styled.div` display: flex; align-items: center; justify-content: space-between; font-size: 14px; color: white; margin-bottom: 10px; `; const InfoKey = styled.div` color: #979abe; `; const { expand, addAction, toast, chainId, nativeCurrency, onSuccess, dexConfig, account, prices, multicall, multicallAddress, TOKENS, } = props; const data = props.data || {}; // console.log("DATA--", data); let TABS = ["Add Collateral", "Remove Collateral", "Borrow", "Repay"]; State.init({ tab: TABS[0], // infos: [], contentStatus: "", borrowLimitUSD: 0, maxWithdraw: 0, }); const Infos = [ "Your Collateral", "Your Borrow", "Your Lend", "Max LTV", "Liquidation Fee", ]; if (!state.tab) return null; function formatValue(value, digits) { if (isNaN(Number(value))) return ""; if (Number(value) === 0) return "0"; return Big(value || 0).lt(0.01) ? "< 0.01" : `${Number(value).toFixed(digits || 2)}`; } const onAmountChange = (amount) => { if (isNaN(Number(amount))) return; const isZero = Big(amount || 0).eq(0); if (isZero) { State.update({ amount, }); return; } const params = { amount }; params.isAssetBigerThanBalance = Big(amount || 0).gt( data.userUnderlyingBalance || 0 ); State.update(params); }; function getPrice(symbol) { if (symbol === "weETH.mode") { return prices["weETH"]; } return prices[symbol] || 1; } function calcMaxWithdraw(collateralAmount, borrowAmount, maxLTV, exchangeRate) { console.log( "calcMaxWithdraw--", collateralAmount, borrowAmount, maxLTV, exchangeRate ); if (!Big(collateralAmount).gt(0)) return 0; const EXCHANGE_PRECISION = 1000000000000000000; const LTV_PRECISION = 100000; const MIN_HF = 1.05; const shouldRemainedCollateral = Big(borrowAmount) .times(1.0001) // .times(LTV_PRECISION) .times(exchangeRate) .div(EXCHANGE_PRECISION) .div(maxLTV) .times(MIN_HF); // ((borrowAmount * 1.0001 * LTV_PRECISION * exchangeRate) / // EXCHANGE_PRECISION / // maxLTV) * // MIN_HF; console.log( "shouldRemainedCollateral---", shouldRemainedCollateral.toString() ); const maxWithdrawAmount = Big(collateralAmount).minus( shouldRemainedCollateral ); console.log("maxWithdrawAmount---", maxWithdrawAmount.toFixed(18, 0)); return maxWithdrawAmount.toFixed(data.TOKEN_A.decimals, 0); } useEffect(() => { const collateralUSD = Big(data.yourCollateral || 0).times( Big(getPrice(data.TOKEN_A.symbol)) ); const borrowUSD = Big(data.yourBorrow || 0).times( Big(getPrice(data.TOKEN_B.symbol)) ); const _borrowLimitUSD = collateralUSD .times(Big(data.maxLTV || 0)) .div(1.11) .minus(borrowUSD); // console.log("borrowLimitUSD--", _borrowLimitUSD.toFixed()); let _maxWithdraw = calcMaxWithdraw( data.yourCollateral, data.yourBorrow, data.maxLTV, data.exchangeRate ); // if (Big(data.yourCollateralUSD).gt(0)) { // const shouldRemainedCollateral = Big(data.yourBorrowUSD || 0) // .times(1.0001) // .div(data.maxLTV) // .div(1.018) // // .div(data.exchangeRate) // .times(1.05); // _maxWithdraw = Big(data.yourCollateralUSD) // .minus(shouldRemainedCollateral) // .div(prices[data.TOKEN_A.symbol]) // .toFixed(18, 0); // } else { // _maxWithdraw = 0; // } State.update({ borrowLimitUSD: _borrowLimitUSD.lte(0) ? Big(0) : _borrowLimitUSD, maxWithdraw: _maxWithdraw, }); }, [data]); function renderInfo() { return Infos.map((item) => { switch (item) { case "Your Collateral": return ( <InfoWrap> <InfoKey>{item}:</InfoKey> {formatValue(data.yourCollateral, 2)} {data.TOKEN_A.symbol} $ {Big(data.yourCollateral || 0) .times(Big(getPrice(data.TOKEN_A.symbol))) .toFixed(2)} </InfoWrap> ); case "Your Borrow": return ( <InfoWrap> <InfoKey>{item}:</InfoKey> {formatValue(data.yourBorrow, 2)} {data.TOKEN_B.symbol} $ {Big(data.yourBorrow || 0) .times(Big(getPrice(data.TOKEN_B.symbol))) .toFixed(2)} </InfoWrap> ); case "Your Lend": return ( <InfoWrap> <InfoKey>{item}:</InfoKey> {formatValue(data.yourLends, 2)} {data.TOKEN_B.symbol} $ {Big(data.yourLends || 0) .times(Big(getPrice(data.TOKEN_B.symbol))) .toFixed(2)} </InfoWrap> ); case "Max LTV": return ( <InfoWrap> <InfoKey>{item}:</InfoKey> {Number(data.maxLTV * 100).toFixed()}% </InfoWrap> ); case "Liquidation Fee": return ( <InfoWrap> <InfoKey>{item}:</InfoKey> {Number(data.liquidationFee * 100).toFixed()}% </InfoWrap> ); default: break; } }); } function bigMin(_a, _b) { const a = Big(_a || 0); const b = Big(_b || 0); return a.gt(b) ? b : a; } return ( <StyledBox className={expand ? "expand" : ""}> <StyledWrapper className={expand ? "expand" : ""}> <StyledHeader> <StyledTabs> {TABS.map((tab) => ( <StyledTab key={tab} className={tab === state.tab ? "active" : ""} onClick={() => { State.update({ tab, amount: "" }); }} > {tab} </StyledTab> ))} </StyledTabs> </StyledHeader> <StyledContent> <StyledInfo> <StyledInfoContent>{renderInfo()}</StyledInfoContent> </StyledInfo> <div className={state.contentStatus}> {state.tab === "Add Collateral" ? ( <Widget src="bluebiu.near/widget/Lending.MarketInput" props={{ icon: data.TOKEN_A.icon, symbol: data.TOKEN_A.symbol, balance: TOKENS?.find( (item) => item.symbol === data.TOKEN_A.symbol ).balance, price: prices[data.TOKEN_A.symbol], amount: state.amount, onChange: (val) => { onAmountChange(val); }, }} /> ) : null} {state.tab === "Remove Collateral" ? ( <Widget src="bluebiu.near/widget/Lending.MarketInput" props={{ icon: data.TOKEN_A.icon, symbol: data.TOKEN_A.symbol, balance: state.maxWithdraw, price: prices[data.TOKEN_A.symbol], amount: state.amount, onChange: (val) => { onAmountChange(val); }, }} /> ) : null} {state.tab === "Borrow" ? ( <Widget src="bluebiu.near/widget/Lending.MarketInput" props={{ icon: data.TOKEN_B.icon, symbol: data.TOKEN_B.symbol, balance: state.borrowLimitUSD .div(Big(getPrice(data.TOKEN_B.symbol))) .toFixed(6, 0), price: prices[data.TOKEN_B.symbol], amount: state.amount, onChange: (val) => { onAmountChange(val); }, }} /> ) : null} {state.tab === "Repay" ? ( <Widget src="bluebiu.near/widget/Lending.MarketInput" props={{ icon: data.TOKEN_B.icon, symbol: data.TOKEN_B.symbol, balance: bigMin( TOKENS?.find((item) => item.symbol === data.TOKEN_B.symbol) .balance, data.yourBorrow ), price: prices[data.TOKEN_B.symbol], amount: state.amount, onChange: (val) => { onAmountChange(val); }, }} /> ) : null} <StyledButtonWrapper> <div style={{ flexGrow: 1 }}> <Widget src="bluebiu.near/widget/Lending.Sturdy.PoolButton" props={{ ...props, actionText: state.tab, amount: state.amount, isAssetBigerThanBalance: state.isAssetBigerThanBalance, // isDebtBigerThanBalance: state.isDebtBigerThanBalance, addAction, toast, chainId, onSuccess: () => { onSuccess?.(); }, }} /> </div> </StyledButtonWrapper> </div> </StyledContent> </StyledWrapper> </StyledBox> );