Skip to content

Commit 4457620

Browse files
Fix/simplify market detail data fetching (#547)
1 parent d736d15 commit 4457620

File tree

13 files changed

+477
-516
lines changed

13 files changed

+477
-516
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* Hook for managing borrow and repay modal states
3+
* Handles borrow and repay transaction modal flows
4+
*/
5+
6+
import { useState } from "react";
7+
8+
interface BorrowData {
9+
collateral: number;
10+
borrow: number;
11+
}
12+
13+
interface RepayData {
14+
repay: number;
15+
withdraw: number;
16+
}
17+
18+
export interface UseBorrowRepayModalsResult {
19+
// Borrow modal state
20+
showBorrowReviewModal: boolean;
21+
showBorrowSuccessModal: boolean;
22+
lastBorrowData: BorrowData;
23+
openBorrowReview: (collateralAmount: number, borrowAmount: number) => void;
24+
closeBorrowReview: () => void;
25+
showBorrowSuccess: () => void;
26+
closeBorrowSuccess: () => void;
27+
28+
// Repay modal state
29+
showRepayReviewModal: boolean;
30+
showRepaySuccessModal: boolean;
31+
lastRepayData: RepayData;
32+
openRepayReview: (repayAmount: number, withdrawAmount: number) => void;
33+
closeRepayReview: () => void;
34+
showRepaySuccess: () => void;
35+
closeRepaySuccess: () => void;
36+
37+
// Processing state
38+
processing: boolean;
39+
setProcessing: (processing: boolean) => void;
40+
}
41+
42+
/**
43+
* Manages modal states for borrow and repay flows
44+
*/
45+
export function useBorrowRepayModals(): UseBorrowRepayModalsResult {
46+
// Borrow modal state
47+
const [showBorrowReviewModal, setShowBorrowReviewModal] = useState(false);
48+
const [showBorrowSuccessModal, setShowBorrowSuccessModal] = useState(false);
49+
const [lastBorrowData, setLastBorrowData] = useState<BorrowData>({
50+
collateral: 0,
51+
borrow: 0,
52+
});
53+
54+
// Repay modal state
55+
const [showRepayReviewModal, setShowRepayReviewModal] = useState(false);
56+
const [showRepaySuccessModal, setShowRepaySuccessModal] = useState(false);
57+
const [lastRepayData, setLastRepayData] = useState<RepayData>({
58+
repay: 0,
59+
withdraw: 0,
60+
});
61+
62+
// Processing state
63+
const [processing, setProcessing] = useState(false);
64+
65+
return {
66+
// Borrow modal
67+
showBorrowReviewModal,
68+
showBorrowSuccessModal,
69+
lastBorrowData,
70+
openBorrowReview: (collateralAmount: number, borrowAmount: number) => {
71+
setLastBorrowData({ collateral: collateralAmount, borrow: borrowAmount });
72+
setShowBorrowReviewModal(true);
73+
},
74+
closeBorrowReview: () => setShowBorrowReviewModal(false),
75+
showBorrowSuccess: () => {
76+
setShowBorrowReviewModal(false);
77+
setShowBorrowSuccessModal(true);
78+
},
79+
closeBorrowSuccess: () => setShowBorrowSuccessModal(false),
80+
81+
// Repay modal
82+
showRepayReviewModal,
83+
showRepaySuccessModal,
84+
lastRepayData,
85+
openRepayReview: (repayAmount: number, withdrawAmount: number) => {
86+
setLastRepayData({ repay: repayAmount, withdraw: withdrawAmount });
87+
setShowRepayReviewModal(true);
88+
},
89+
closeRepayReview: () => setShowRepayReviewModal(false),
90+
showRepaySuccess: () => {
91+
setShowRepayReviewModal(false);
92+
setShowRepaySuccessModal(true);
93+
},
94+
closeRepaySuccess: () => setShowRepaySuccessModal(false),
95+
96+
// Processing
97+
processing,
98+
setProcessing,
99+
};
100+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/**
2+
* Hook for borrow and repay transaction handlers
3+
*/
4+
5+
import { parseUnits } from "viem";
6+
import { useWalletClient } from "wagmi";
7+
8+
import { CONTRACTS } from "../../../../config/contracts";
9+
import {
10+
repayDebtFull,
11+
repayDebtPartial,
12+
withdrawCollateralFromPosition,
13+
} from "../../../../services/position/positionTransactionService";
14+
15+
interface UseBorrowRepayTransactionsProps {
16+
hasPosition: boolean;
17+
userPosition: {
18+
positionId: string;
19+
marketId: string;
20+
collateral: bigint;
21+
borrowAssets: bigint;
22+
borrowShares: bigint;
23+
} | null;
24+
currentLoanAmount: number;
25+
refetch: () => Promise<void>;
26+
onBorrowSuccess: () => void;
27+
onRepaySuccess: () => void;
28+
setProcessing: (processing: boolean) => void;
29+
}
30+
31+
export interface UseBorrowRepayTransactionsResult {
32+
handleConfirmBorrow: () => Promise<void>;
33+
handleConfirmRepay: (
34+
repayAmount: number,
35+
withdrawAmount: number,
36+
) => Promise<void>;
37+
}
38+
39+
/**
40+
* Handles borrow and repay transaction logic
41+
*/
42+
export function useBorrowRepayTransactions({
43+
hasPosition,
44+
userPosition,
45+
currentLoanAmount,
46+
refetch,
47+
onBorrowSuccess,
48+
onRepaySuccess,
49+
setProcessing,
50+
}: UseBorrowRepayTransactionsProps): UseBorrowRepayTransactionsResult {
51+
const { data: walletClient } = useWalletClient();
52+
const chain = walletClient?.chain;
53+
54+
const handleConfirmBorrow = async () => {
55+
setProcessing(true);
56+
try {
57+
// TODO: Implement real borrow logic
58+
await new Promise((resolve) => setTimeout(resolve, 2000));
59+
onBorrowSuccess();
60+
} catch {
61+
// Handle error silently
62+
} finally {
63+
setProcessing(false);
64+
}
65+
};
66+
67+
const handleConfirmRepay = async (
68+
repayAmount: number,
69+
withdrawAmount: number,
70+
) => {
71+
// If user has a position, use real repay logic
72+
if (hasPosition && userPosition) {
73+
setProcessing(true);
74+
try {
75+
// Validate wallet connection
76+
if (!walletClient || !chain) {
77+
throw new Error("Wallet not connected. Please connect your wallet.");
78+
}
79+
80+
const { positionId, marketId } = userPosition;
81+
82+
// Determine if this is a full or partial repayment
83+
const tolerance = 0.01; // 0.01 USDC tolerance
84+
const isFullRepayment =
85+
Math.abs(repayAmount - currentLoanAmount) < tolerance;
86+
87+
// Step 1: Repay debt
88+
if (isFullRepayment) {
89+
await repayDebtFull(
90+
walletClient,
91+
chain,
92+
CONTRACTS.VAULT_CONTROLLER,
93+
positionId as `0x${string}`,
94+
marketId,
95+
);
96+
} else {
97+
const repayAmountBigint = parseUnits(repayAmount.toString(), 6);
98+
99+
await repayDebtPartial(
100+
walletClient,
101+
chain,
102+
CONTRACTS.VAULT_CONTROLLER,
103+
positionId as `0x${string}`,
104+
marketId,
105+
repayAmountBigint,
106+
);
107+
}
108+
109+
// Step 2: Withdraw collateral if user requested it
110+
if (withdrawAmount > 0) {
111+
await withdrawCollateralFromPosition(
112+
walletClient,
113+
chain,
114+
CONTRACTS.VAULT_CONTROLLER,
115+
marketId,
116+
);
117+
}
118+
119+
// Refetch position data to update UI
120+
await refetch();
121+
122+
// Success - show success modal
123+
onRepaySuccess();
124+
} catch (error) {
125+
// Show error to user
126+
console.error("Repayment failed:", error);
127+
alert(
128+
`Repayment failed: ${error instanceof Error ? error.message : "Unknown error"}`,
129+
);
130+
} finally {
131+
setProcessing(false);
132+
}
133+
} else {
134+
// Market view - mock repay (user shouldn't actually reach here without position)
135+
setProcessing(true);
136+
try {
137+
await new Promise((resolve) => setTimeout(resolve, 2000));
138+
onRepaySuccess();
139+
} finally {
140+
setProcessing(false);
141+
}
142+
}
143+
};
144+
145+
return {
146+
handleConfirmBorrow,
147+
handleConfirmRepay,
148+
};
149+
}

services/vault/src/components/Market/Detail/hooks/useMarketDetail.ts

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export function useMarketDetail() {
1818
btcPriceUSD,
1919
loading: isMarketLoading,
2020
error: marketError,
21+
refetch,
2122
} = useMarketDetailData(marketId);
2223

2324
const [creationDate, setCreationDate] = useState<string>("Loading...");
@@ -108,20 +109,11 @@ export function useMarketDetail() {
108109
marketData,
109110
]);
110111

111-
const positionData = useMemo<Array<{ label: string; value: string }>>(() => {
112+
const positionData = useMemo<
113+
Array<{ label: string; value: string }> | undefined
114+
>(() => {
112115
if (!userPosition) {
113-
return [
114-
{ label: "Current Loan", value: "0 USDC" },
115-
{ label: "Current Collateral", value: "0 BTC" },
116-
{ label: "Market", value: "BTC/USDC" },
117-
{ label: "Current LTV", value: "0%" },
118-
{
119-
label: "Liquidation LTV",
120-
value: marketConfig
121-
? `${formatLLTV(marketConfig.lltv)}%`
122-
: `${liquidationLtv.toFixed(1)}%`,
123-
},
124-
];
116+
return undefined;
125117
}
126118
const currentLtv =
127119
currentCollateralAmount > 0
@@ -154,6 +146,34 @@ export function useMarketDetail() {
154146
liquidationLtv,
155147
]);
156148

149+
// Format market display values
150+
const marketDisplayValues = useMemo(() => {
151+
if (!marketData) {
152+
return {
153+
totalMarketSize: "?",
154+
totalMarketSizeSubtitle: "?",
155+
totalLiquidity: "?",
156+
totalLiquiditySubtitle: "?",
157+
borrowRate: "?",
158+
};
159+
}
160+
161+
const totalSupplyM = (Number(marketData.totalSupplyAssets) / 1e12).toFixed(
162+
2,
163+
);
164+
const totalBorrowM = (Number(marketData.totalBorrowAssets) / 1e12).toFixed(
165+
2,
166+
);
167+
168+
return {
169+
totalMarketSize: `$${totalSupplyM}M`,
170+
totalMarketSizeSubtitle: `${totalSupplyM}M USDC`,
171+
totalLiquidity: `$${totalBorrowM}M`,
172+
totalLiquiditySubtitle: `${totalBorrowM}M USDC`,
173+
borrowRate: "?",
174+
};
175+
}, [marketData]);
176+
157177
return {
158178
// loading / error
159179
isMarketLoading,
@@ -173,5 +193,9 @@ export function useMarketDetail() {
173193
// derived view
174194
marketAttributes,
175195
positionData,
196+
marketDisplayValues,
197+
198+
// actions
199+
refetch,
176200
} as const;
177201
}

0 commit comments

Comments
 (0)