Skip to content

Commit 8111327

Browse files
feat(packages): pegin flow
1 parent 8b31b33 commit 8111327

File tree

12 files changed

+330
-37
lines changed

12 files changed

+330
-37
lines changed

package-lock.json

Lines changed: 17 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
"dependencies": {
5555
"@morpho-org/blue-sdk": "^5.0.0",
5656
"@morpho-org/blue-sdk-viem": "^4.0.0",
57-
"@tanstack/react-query": "^5.90.2"
57+
"@tanstack/react-query": "^5.90.2",
58+
"usehooks-ts": "^3.1.1"
5859
},
5960
"optionalDependencies": {
6061
"@rollup/rollup-darwin-arm64": "4.52.4"

packages/babylon-core-ui/src/widgets/sections/ActivityCard/ActivityCard.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface ActivityCardData {
3939
label: string;
4040
items: ActivityListItemData[];
4141
}[];
42+
warning?: React.ReactNode;
4243
primaryAction?: ActivityCardActionButton;
4344
secondaryActions?: ActivityCardActionButton[];
4445
}
@@ -72,6 +73,12 @@ export function ActivityCard({ data, className }: ActivityCardProps) {
7273
{data.secondaryActions && data.secondaryActions.length > 0 && (
7374
<ActivityCardActionSection actions={data.secondaryActions} />
7475
)}
76+
77+
{data.warning && (
78+
<div className="mt-3 sm:mt-4">
79+
{data.warning}
80+
</div>
81+
)}
7582
</div>
7683

7784
{data.primaryAction && (

routes/vault/src/components/PeginFlow/usePeginFlowState.ts

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,6 @@
1-
import { useState, useCallback, useMemo } from "react";
2-
import { useChainConnector } from "@babylonlabs-io/wallet-connector";
3-
import type { Hex } from "viem";
1+
import { useState, useCallback } from "react";
42

53
export function usePeginFlowState() {
6-
const ethConnector = useChainConnector('ETH');
7-
const btcConnector = useChainConnector('BTC');
8-
9-
// Get BTC address from connector
10-
const btcAddress = useMemo(() => {
11-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
12-
return (btcConnector as any)?.connectedWallet?.account?.address as string | undefined;
13-
}, [btcConnector]);
14-
15-
// Get ETH address from connector
16-
const connectedAddress = useMemo(() => {
17-
const address = (
18-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
19-
(ethConnector as any)?.connectedWallet?.account?.address ||
20-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
21-
(ethConnector as any)?.connectedWallet?.accounts?.[0]?.address
22-
) as Hex | undefined;
23-
return address;
24-
}, [ethConnector]);
25-
264
// Hardcoded BTC balance (in satoshis) - TODO: Replace with real wallet balance
275
const btcBalanceSat = 500000000; // 5 BTC
286

@@ -49,10 +27,15 @@ export function usePeginFlowState() {
4927
setPeginSignModalOpen(true);
5028
}, []);
5129

52-
// Handle signing success
53-
const handlePeginSignSuccess = useCallback(() => {
30+
// Handle signing success - accepts callback for parent to handle storage
31+
const handlePeginSignSuccess = useCallback((onSuccess?: () => void) => {
5432
setPeginSignModalOpen(false);
5533
setPeginSuccessModalOpen(true);
34+
35+
// Call parent callback if provided
36+
if (onSuccess) {
37+
onSuccess();
38+
}
5639
}, []);
5740

5841
// Handle success modal close
@@ -64,8 +47,6 @@ export function usePeginFlowState() {
6447

6548
return {
6649
// Wallet data
67-
connectedAddress,
68-
btcAddress,
6950
btcBalanceSat,
7051
// Modal states
7152
peginModalOpen,
@@ -82,4 +63,4 @@ export function usePeginFlowState() {
8263
setPeginModalOpen,
8364
setPeginSignModalOpen,
8465
};
85-
}
66+
}

routes/vault/src/components/modals/PeginModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export function PeginModal({ open, onClose, onPegIn, btcBalance = 0 }: PeginModa
115115
return (
116116
<ResponsiveDialog open={open} onClose={handleClose}>
117117
<DialogHeader
118-
title="Peg-in BTC"
118+
title="Deposite BTC"
119119
onClose={handleClose}
120120
className="text-accent-primary"
121121
/>
@@ -237,7 +237,7 @@ export function PeginModal({ open, onClose, onPegIn, btcBalance = 0 }: PeginModa
237237
onClick={handlePegIn}
238238
className="w-full text-sm sm:text-base"
239239
>
240-
Peg-in
240+
Deposit
241241
</Button>
242242
</DialogFooter>
243243
</ResponsiveDialog>

routes/vault/src/components/modals/PeginSignModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export function PeginSignModal({
7171
return (
7272
<ResponsiveDialog open={open} onClose={onClose}>
7373
<DialogHeader
74-
title="Peg-in in Progress"
74+
title="Deposit in Progress"
7575
onClose={onClose}
7676
className="text-accent-primary"
7777
/>

routes/vault/src/components/modals/PeginSuccessModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ export function PeginSuccessModal({
3232
<img
3333
src="/mascot-smile-expression.png"
3434
alt="Success mascot"
35-
className="mx-auto mb-6 size-[300px]"
35+
className="mx-auto mb-6 size-auto"
3636
/>
3737

3838
<Heading variant="h4" className="mb-4 text-xl sm:text-2xl">
39-
BTC Peg-in Successful
39+
BTC Deposit Successful
4040
</Heading>
4141

4242
<Text variant="body1" className="text-sm text-accent-secondary sm:text-base">

routes/vault/src/hooks/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
export { usePeginRequests } from './usePeginRequests';
66
export type { UsePeginRequestsResult } from './usePeginRequests';
77
export { useVaultProviders } from './useVaultProviders';
8-
export { usePeginForm } from './usePeginForm';
8+
export { usePeginForm } from './usePeginForm';
9+
export { usePeginStorage } from './usePeginStorage';
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* Hook for managing peg-in local storage
3+
*
4+
* Similar to simple-staking's useDelegationStorage pattern:
5+
* - Merges pending peg-ins from localStorage with confirmed peg-ins from API
6+
* - Automatically removes confirmed peg-ins from localStorage
7+
* - Cleans up old pending peg-ins
8+
*/
9+
10+
import { useCallback, useEffect, useMemo } from 'react';
11+
import { useLocalStorage } from 'usehooks-ts';
12+
import type { VaultActivity } from '../mockData/vaultActivities';
13+
import {
14+
type PendingPeginRequest,
15+
filterPendingPegins,
16+
} from '../storage/peginStorage';
17+
import { bitcoinIcon } from '../assets';
18+
19+
interface UsePeginStorageParams {
20+
ethAddress: string;
21+
confirmedPegins: VaultActivity[]; // Peg-ins from API/blockchain
22+
}
23+
24+
export function usePeginStorage({
25+
ethAddress,
26+
confirmedPegins,
27+
}: UsePeginStorageParams) {
28+
const storageKey = `vault-pending-pegins-${ethAddress}`;
29+
30+
// Store pending peg-ins in localStorage
31+
const [pendingPegins = [], setPendingPegins] = useLocalStorage<
32+
PendingPeginRequest[]
33+
>(storageKey, []);
34+
35+
// Create a map of confirmed peg-in IDs for quick lookup
36+
const confirmedPeginMap = useMemo(() => {
37+
return confirmedPegins.reduce(
38+
(acc, pegin) => ({
39+
...acc,
40+
[pegin.id]: pegin,
41+
}),
42+
{} as Record<string, VaultActivity>,
43+
);
44+
}, [confirmedPegins]);
45+
46+
// Sync: Remove pending peg-ins that are now confirmed
47+
useEffect(() => {
48+
if (!ethAddress) return;
49+
50+
const confirmedIds = Object.keys(confirmedPeginMap);
51+
const filteredPegins = filterPendingPegins(pendingPegins, confirmedIds);
52+
53+
// Only update if something changed
54+
if (filteredPegins.length !== pendingPegins.length) {
55+
setPendingPegins(filteredPegins);
56+
}
57+
}, [ethAddress, confirmedPeginMap, pendingPegins, setPendingPegins]);
58+
59+
// Convert pending peg-ins to VaultActivity format
60+
const pendingActivities: VaultActivity[] = useMemo(() => {
61+
return pendingPegins
62+
.filter((pegin: PendingPeginRequest) => !confirmedPeginMap[pegin.id]) // Don't show if already confirmed
63+
.map((pegin: PendingPeginRequest) => ({
64+
id: pegin.id,
65+
collateral: {
66+
amount: pegin.amount,
67+
symbol: 'BTC',
68+
icon: bitcoinIcon,
69+
},
70+
status: {
71+
label: 'Pending',
72+
variant: 'pending' as const,
73+
},
74+
providers: pegin.providers.map((providerId: string) => ({
75+
id: providerId,
76+
name: providerId, // TODO: Map to actual provider names
77+
icon: undefined,
78+
})),
79+
action: {
80+
label: 'Borrow USDC',
81+
onClick: () => console.log('Borrow from pending peg-in:', pegin.id),
82+
},
83+
isPending: true, // Flag to show callout message
84+
}));
85+
}, [pendingPegins, confirmedPeginMap]);
86+
87+
// Merge pending and confirmed activities
88+
const allActivities: VaultActivity[] = useMemo(() => {
89+
return [...pendingActivities, ...confirmedPegins];
90+
}, [pendingActivities, confirmedPegins]);
91+
92+
// Add a new pending peg-in
93+
const addPendingPegin = useCallback(
94+
(pegin: Omit<PendingPeginRequest, 'timestamp' | 'status'>) => {
95+
if (!ethAddress) return;
96+
97+
const newPegin: PendingPeginRequest = {
98+
...pegin,
99+
timestamp: Date.now(),
100+
status: 'pending',
101+
};
102+
103+
setPendingPegins((prev: PendingPeginRequest[]) => [...prev, newPegin]);
104+
},
105+
[ethAddress, setPendingPegins],
106+
);
107+
108+
// Remove a pending peg-in manually
109+
const removePendingPegin = useCallback(
110+
(peginId: string) => {
111+
setPendingPegins((prev: PendingPeginRequest[]) => prev.filter((p: PendingPeginRequest) => p.id !== peginId));
112+
},
113+
[setPendingPegins],
114+
);
115+
116+
// Clear all pending peg-ins
117+
const clearPendingPegins = useCallback(() => {
118+
setPendingPegins([]);
119+
}, [setPendingPegins]);
120+
121+
return {
122+
allActivities,
123+
pendingPegins,
124+
pendingActivities,
125+
addPendingPegin,
126+
removePendingPegin,
127+
clearPendingPegins,
128+
};
129+
}

routes/vault/src/mockData/vaultActivities.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ export interface VaultActivity {
5858
borrowAmount: bigint;
5959
active: boolean;
6060
};
61+
// Pending peg-in flags
62+
isPending?: boolean; // Flag to show pending callout message
63+
pendingMessage?: string; // Custom pending message
6164
}
6265

6366
const bitcoinIconDataUri = "data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='%23FF7C2A' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M23.638 14.904c-1.602 6.43-8.113 10.34-14.542 8.736C2.67 22.05-1.244 15.525.362 9.105 1.962 2.67 8.475-1.243 14.9.358c6.43 1.605 10.342 8.115 8.738 14.548v-.002zm-6.35-4.613c.24-1.59-.974-2.45-2.64-3.03l.54-2.153-1.315-.33-.525 2.107c-.345-.087-.705-.167-1.064-.25l.526-2.127-1.32-.33-.54 2.165c-.285-.067-.565-.132-.84-.2l-1.815-.45-.35 1.407s.975.225.955.236c.535.136.63.486.615.766l-1.477 5.92c-.075.166-.24.406-.614.314.015.02-.96-.24-.96-.24l-.66 1.51 1.71.426.93.242-.54 2.19 1.32.327.54-2.17c.36.1.705.19 1.05.273l-.51 2.154 1.32.33.545-2.19c2.24.427 3.93.257 4.64-1.774.57-1.637-.03-2.58-1.217-3.196.854-.193 1.5-.76 1.68-1.93h.01zm-3.01 4.22c-.404 1.64-3.157.75-4.05.53l.72-2.9c.896.23 3.757.67 3.33 2.37zm.41-4.24c-.37 1.49-2.662.735-3.405.55l.654-2.64c.744.18 3.137.524 2.75 2.084v.006z'/%3E%3C/svg%3E";

0 commit comments

Comments
 (0)