Skip to content

Commit efe273f

Browse files
authored
Merge pull request #227 from blend-capital/fix-loading-bug
Fix loading bug
2 parents 7b8125e + 3ff96a5 commit efe273f

File tree

10 files changed

+173
-31
lines changed

10 files changed

+173
-31
lines changed

package-lock.json

Lines changed: 13 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "blend-ui",
3-
"version": "2.4.0",
3+
"version": "2.4.1",
44
"private": true,
55
"type": "module",
66
"scripts": {

src/components/markets/MarketCard.tsx

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { StackedTextHLBox } from '../common/StackedTextHLBox';
2424
import { TokenIcon } from '../common/TokenIcon';
2525
import { PoolHeader } from '../pool/PoolHeader';
2626
import { PoolHealthBanner } from '../pool/PoolHealthBanner';
27+
import { PoolLoadError } from '../pool/PoolLoadErrorBanner';
2728
import { MarketCardCollapse } from './MarketCardCollapse';
2829

2930
export interface MarketCardProps extends PoolComponentProps {
@@ -44,10 +45,10 @@ export const MarketCard: React.FC<MarketCardProps> = ({ poolId, index, onLoaded,
4445
const theme = useTheme();
4546
const { trackPool, viewType } = useSettings();
4647

47-
const { data: poolMeta } = usePoolMeta(poolId);
48+
const { data: poolMeta, error: poolMetaError, isError: isPoolMetaError } = usePoolMeta(poolId);
4849
const { data: backstop } = useBackstop(poolMeta?.version);
49-
const { data: pool } = usePool(poolMeta);
50-
const { data: poolOracle } = usePoolOracle(pool);
50+
const { data: pool, isError: isPoolError } = usePool(poolMeta);
51+
const { data: poolOracle, isError: isOracleError } = usePoolOracle(pool);
5152
const { data: backstopPool } = useBackstopPool(poolMeta);
5253
const [expand, setExpand] = useState(false);
5354
const [rotateArrow, setRotateArrow] = useState(false);
@@ -58,14 +59,65 @@ export const MarketCard: React.FC<MarketCardProps> = ({ poolId, index, onLoaded,
5859
const tokenMetadataList = useTokenMetadataList(pool ? Array.from(pool.reserves.keys()) : []);
5960

6061
useEffect(() => {
62+
// Handle poolMeta errors — call onLoaded so progressive loading doesn't stall
63+
if (isPoolMetaError) {
64+
onLoaded(poolId, index, {
65+
name: '',
66+
poolTvl: 0,
67+
backstopTvl: 0,
68+
tokenMetadataList: [],
69+
});
70+
return;
71+
}
72+
73+
// Handle pool load errors when poolMeta is available
74+
if (poolMeta !== undefined && isPoolError) {
75+
onLoaded(poolId, index, {
76+
name: poolMeta.name,
77+
poolTvl: 0,
78+
backstopTvl: 0,
79+
tokenMetadataList: [],
80+
});
81+
trackPool(poolMeta);
82+
return;
83+
}
84+
85+
// Handle oracle errors — render card with unknown TVL but real backstop data
86+
if (
87+
poolMeta !== undefined &&
88+
pool !== undefined &&
89+
backstopPool !== undefined &&
90+
backstop !== undefined &&
91+
isOracleError
92+
) {
93+
const backstopPoolEst = BackstopPoolEst.build(
94+
backstop.backstopToken,
95+
backstopPool.poolBalance
96+
);
97+
const processedTokenMetadata: ReserveTokenMetadata[] = tokenMetadataList
98+
.filter((result) => result.data !== undefined)
99+
.map((result) => result.data!)
100+
.filter((data): data is ReserveTokenMetadata => data !== null);
101+
102+
onLoaded(poolId, index, {
103+
name: poolMeta.name,
104+
poolTvl: 0,
105+
backstopTvl: backstopPoolEst?.totalSpotValue ?? 0,
106+
tokenMetadataList: processedTokenMetadata,
107+
});
108+
trackPool(poolMeta);
109+
return;
110+
}
111+
112+
// All data loaded successfully
61113
if (
62114
poolMeta !== undefined &&
63115
pool !== undefined &&
64116
backstopPool !== undefined &&
65117
backstop !== undefined &&
66118
poolOracle !== undefined
67119
) {
68-
const poolEst = poolOracle ? PoolEstimate.build(pool.reserves, poolOracle) : undefined;
120+
const poolEst = PoolEstimate.build(pool.reserves, poolOracle);
69121
const backstopPoolEst = BackstopPoolEst.build(
70122
backstop.backstopToken,
71123
backstopPool.poolBalance
@@ -77,18 +129,58 @@ export const MarketCard: React.FC<MarketCardProps> = ({ poolId, index, onLoaded,
77129

78130
onLoaded(poolId, index, {
79131
name: poolMeta.name,
80-
poolTvl: poolEst ? poolEst.totalSupply - poolEst.totalBorrowed : 0,
132+
poolTvl: poolEst.totalSupply - poolEst.totalBorrowed,
81133
backstopTvl: backstopPoolEst?.totalSpotValue ?? 0,
82134
tokenMetadataList: processedTokenMetadata,
83135
});
84136
trackPool(poolMeta);
85137
}
86-
}, [pool, backstopPool, backstop, poolOracle, tokenMetadataList]);
138+
}, [
139+
pool,
140+
backstopPool,
141+
backstop,
142+
poolOracle,
143+
tokenMetadataList,
144+
isOracleError,
145+
isPoolError,
146+
isPoolMetaError,
147+
]);
148+
149+
// poolMeta failed to load (other error) — show error banner with contract ID
150+
if (isPoolMetaError) {
151+
return (
152+
<Section
153+
width={SectionSize.FULL}
154+
sx={{ flexDirection: 'column', marginBottom: '12px', ...sx }}
155+
>
156+
<PoolLoadError poolId={poolId} />
157+
</Section>
158+
);
159+
}
160+
161+
// Pool data failed to load but poolMeta is available — show header + error banner
162+
if (poolMeta !== undefined && isPoolError) {
163+
return (
164+
<Section
165+
width={SectionSize.FULL}
166+
sx={{ flexDirection: 'column', marginBottom: '12px', ...sx }}
167+
>
168+
<Row>
169+
<PoolHeader
170+
name={poolMeta.name}
171+
version={poolMeta.version}
172+
sx={{ margin: '6px', padding: '6px' }}
173+
/>
174+
</Row>
175+
<PoolLoadError poolId={poolId} poolName={poolMeta.name} />
176+
</Section>
177+
);
178+
}
87179

180+
// Still loading — no errors yet, data not ready
88181
if (
89182
poolMeta === undefined ||
90183
pool === undefined ||
91-
poolOracle === undefined ||
92184
backstopPool === undefined ||
93185
backstop === undefined
94186
) {

src/components/markets/MarketCardCollapse.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { ReserveList } from './ReserveList';
2323

2424
export interface MarketCardCollapseProps extends BoxProps {
2525
pool: Pool;
26-
oracle: PoolOracle;
26+
oracle: PoolOracle | undefined;
2727
poolEst: PoolEstimate | undefined;
2828
backstopPool: BackstopPool;
2929
backstopPoolEst: BackstopPoolEst;
@@ -228,7 +228,7 @@ export const MarketCardCollapse: React.FC<MarketCardCollapseProps> = ({
228228
flexDirection: 'row',
229229
}}
230230
>
231-
{`$${toBalance(pool.metadata.minCollateral, oracle.decimals)}`}
231+
{`$${toBalance(pool.metadata.minCollateral, oracle?.decimals)}`}
232232
</Typography>
233233
</Section>
234234
</Row>

src/components/markets/MarketsList.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,12 @@ export const MarketsList: React.FC<MarketListProps> = ({ version }) => {
141141
});
142142

143143
// Update index for progressive loading
144-
if (index >= currentIndex) {
145-
setCurrentIndex(Math.min(currentIndex + 1, safeRewardZone.length));
146-
}
144+
setCurrentIndex((prev) => {
145+
if (index >= prev) {
146+
return Math.min(prev + 1, safeRewardZone.length);
147+
}
148+
return prev;
149+
});
147150
}
148151

149152
// Handle filter changes from MarketFilter component

src/components/pool/PoolHealthBanner.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,22 @@ import { Box } from '@mui/material';
22
import { usePool, usePoolMeta, usePoolOracle } from '../../hooks/api';
33
import { PoolComponentProps } from '../common/PoolComponentProps';
44
import { Row } from '../common/Row';
5+
import { PoolLoadError } from './PoolLoadErrorBanner';
56
import { PoolOracleError } from './PoolOracleErrorBanner';
67
import { PoolStatusBanner } from './PoolStatusBanner';
78

89
export const PoolHealthBanner: React.FC<PoolComponentProps> = ({ poolId, ...props }) => {
9-
const { data: poolMeta } = usePoolMeta(poolId);
10-
const { data: pool } = usePool(poolMeta);
10+
const { data: poolMeta, isError: isPoolMetaError } = usePoolMeta(poolId);
11+
const { data: pool, isError: isPoolError } = usePool(poolMeta);
1112
const { isError: isOracleError } = usePoolOracle(pool);
1213

1314
return (
1415
<Box sx={{ width: '100%', display: 'flex', flexDirection: 'column' }}>
15-
<PoolStatusBanner status={pool?.metadata?.status} />
16+
{isPoolMetaError || isPoolError ? (
17+
<PoolLoadError poolId={poolId} poolName={poolMeta?.name} />
18+
) : (
19+
<PoolStatusBanner status={pool?.metadata?.status} />
20+
)}
1621
{isOracleError && (
1722
<Row>
1823
<PoolOracleError />
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import WarningIcon from '@mui/icons-material/Warning';
2+
import { Box, Typography, useTheme } from '@mui/material';
3+
import { toCompactAddress } from '../../utils/formatter';
4+
5+
export interface PoolLoadErrorProps {
6+
poolId: string;
7+
poolName?: string;
8+
}
9+
10+
export const PoolLoadError: React.FC<PoolLoadErrorProps> = ({ poolId, poolName }) => {
11+
const theme = useTheme();
12+
const displayName = poolName ? `${poolName} pool` : toCompactAddress(poolId);
13+
return (
14+
<Box
15+
sx={{
16+
width: '100%',
17+
display: 'flex',
18+
margin: '6px',
19+
padding: '12px',
20+
justifyContent: 'space-between',
21+
alignItems: 'center',
22+
paddingRight: '20px',
23+
borderRadius: '4px',
24+
color: theme.palette.warning.main,
25+
backgroundColor: theme.palette.warning.opaque,
26+
}}
27+
>
28+
<Box sx={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center' }}>
29+
<WarningIcon sx={{ marginRight: '6px' }} />
30+
<Typography variant="body2">
31+
{`${displayName} failed to load. Please check back later.`}
32+
</Typography>
33+
</Box>
34+
</Box>
35+
);
36+
};

src/contexts/wallet.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ export const WalletProvider: React.FC<React.PropsWithChildren> = ({ children })
453453
const simResponse = await simulateOperation(operation);
454454
const assembled_tx = rpc.assembleTransaction(transaction, simResponse).build();
455455
const extended_tx = addReflectorEntries(assembled_tx.toXDR());
456+
console.log('Sending transaction to wallet: ', extended_tx);
456457
const signedTx = await sign(extended_tx);
457458
const tx = new Transaction(signedTx, network.passphrase);
458459
await sendTransaction(tx);

src/pages/dashboard.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@ const Dashboard: NextPage = () => {
3131
const { poolId } = router.query;
3232
const safePoolId = typeof poolId == 'string' && /^[0-9A-Z]{56}$/.test(poolId) ? poolId : '';
3333

34-
const { data: poolMeta, error: poolError } = usePoolMeta(safePoolId);
35-
const { data: pool } = usePool(poolMeta);
34+
const {
35+
data: poolMeta,
36+
error: poolMetaError,
37+
isError: isPoolMetaError,
38+
} = usePoolMeta(safePoolId);
39+
const { data: pool, isError: isPoolError } = usePool(poolMeta);
3640
const { data: poolOracle, isError: isOracleError } = usePoolOracle(pool);
3741
const { data: userPoolData } = usePoolUser(pool);
3842

@@ -53,7 +57,7 @@ const Dashboard: NextPage = () => {
5357
}
5458
};
5559

56-
if (poolError?.message === NOT_BLEND_POOL_ERROR_MESSAGE) {
60+
if (poolMetaError?.message === NOT_BLEND_POOL_ERROR_MESSAGE) {
5761
return <NotPoolBar poolId={safePoolId} />;
5862
}
5963

src/utils/formatter.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ export function toBalance(
2323
} else if (typeof amount === 'number') {
2424
numValue = amount;
2525
} else {
26-
console.error('Invalid toBalance input. Must provide decimals if amount is a bigint.');
2726
return '--';
2827
}
2928

0 commit comments

Comments
 (0)