Skip to content

Commit 50a1e6e

Browse files
committed
fix: shield plan token approval amount incorrect when plan change
1 parent d788715 commit 50a1e6e

File tree

2 files changed

+87
-71
lines changed

2 files changed

+87
-71
lines changed

ui/hooks/subscription/useSubscriptionPricing.ts

Lines changed: 66 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ export const useAvailableTokenBalances = (params: {
4343
paymentChains?: ChainPaymentInfo[];
4444
price?: ProductPrice;
4545
productType: ProductType;
46-
}): TokenWithApprovalAmount[] => {
46+
}): {
47+
availableTokenBalances: TokenWithApprovalAmount[];
48+
pending: boolean;
49+
error: Error | undefined;
50+
} => {
4751
const { paymentChains, price, productType } = params;
4852

4953
const paymentChainIds = useMemo(
@@ -70,10 +74,6 @@ export const useAvailableTokenBalances = (params: {
7074
// Poll and update evm balances for payment chains
7175
pollAndUpdateEvmBalances({ chainIds: paymentChainIds });
7276

73-
const [availableTokenBalances, setAvailableTokenBalances] = useState<
74-
TokenWithApprovalAmount[]
75-
>([]);
76-
7777
const validTokenBalances = useMemo(() => {
7878
return evmBalances.filter((token) => {
7979
const supportedTokensForChain =
@@ -96,72 +96,74 @@ export const useAvailableTokenBalances = (params: {
9696
});
9797
}, [evmBalances, paymentChainTokenMap]);
9898

99-
useEffect(() => {
99+
const {
100+
value: availableTokenBalances,
101+
pending,
102+
error,
103+
} = useAsyncResult(async (): Promise<TokenWithApprovalAmount[]> => {
100104
if (!price || !paymentChainTokenMap) {
101-
return;
105+
return [];
102106
}
103107

104-
const getAvailableTokenBalances = async () => {
105-
const availableTokens: TokenWithApprovalAmount[] = [];
106-
107-
const cryptoApprovalAmounts = await Promise.all(
108-
validTokenBalances.map((token) => {
109-
const tokenPaymentInfo = paymentChainTokenMap?.[
110-
token.chainId as Hex
111-
]?.find(
112-
(t) => t.address.toLowerCase() === token.address.toLowerCase(),
108+
const availableTokens: TokenWithApprovalAmount[] = [];
109+
110+
const cryptoApprovalAmounts = await Promise.all(
111+
validTokenBalances.map((token) => {
112+
const tokenPaymentInfo = paymentChainTokenMap?.[
113+
token.chainId as Hex
114+
]?.find((t) => t.address.toLowerCase() === token.address.toLowerCase());
115+
if (!tokenPaymentInfo) {
116+
log.error(
117+
'[useAvailableTokenBalances] tokenPaymentInfo not found',
118+
token,
113119
);
114-
if (!tokenPaymentInfo) {
115-
log.error(
116-
'[useAvailableTokenBalances] tokenPaymentInfo not found',
117-
token,
118-
);
119-
return null;
120-
}
121-
return getSubscriptionCryptoApprovalAmount({
122-
chainId: token.chainId as Hex,
123-
paymentTokenAddress: token.address as Hex,
124-
productType,
125-
interval: price.interval,
126-
});
127-
}),
128-
);
129-
130-
cryptoApprovalAmounts.forEach((amount, index) => {
131-
const token = validTokenBalances[index];
132-
if (!token.balance) {
133-
return;
134-
}
135-
// NOTE: we are using stable coin for subscription atm, so we need to scale the balance by the decimals
136-
const scaledFactor = 10n ** 6n;
137-
const scaledBalance =
138-
BigInt(Math.round(Number(token.balance) * Number(scaledFactor))) /
139-
scaledFactor;
140-
const tokenHasEnoughBalance =
141-
amount &&
142-
scaledBalance * BigInt(10 ** token.decimals) >=
143-
BigInt(amount.approveAmount);
144-
if (tokenHasEnoughBalance) {
145-
availableTokens.push({
146-
...token,
147-
approvalAmount: {
148-
approveAmount: amount.approveAmount,
149-
chainId: token.chainId as Hex,
150-
paymentAddress: amount.paymentAddress,
151-
paymentTokenAddress: amount.paymentTokenAddress,
152-
},
153-
type: token.isNative ? AssetType.native : AssetType.token,
154-
} as TokenWithApprovalAmount);
120+
return null;
155121
}
156-
});
157-
158-
setAvailableTokenBalances(availableTokens);
159-
};
122+
return getSubscriptionCryptoApprovalAmount({
123+
chainId: token.chainId as Hex,
124+
paymentTokenAddress: token.address as Hex,
125+
productType,
126+
interval: price.interval,
127+
});
128+
}),
129+
);
130+
131+
cryptoApprovalAmounts.forEach((amount, index) => {
132+
const token = validTokenBalances[index];
133+
if (!token.balance) {
134+
return;
135+
}
136+
// NOTE: we are using stable coin for subscription atm, so we need to scale the balance by the decimals
137+
const scaledFactor = 10n ** 6n;
138+
const scaledBalance =
139+
BigInt(Math.round(Number(token.balance) * Number(scaledFactor))) /
140+
scaledFactor;
141+
const tokenHasEnoughBalance =
142+
amount &&
143+
scaledBalance * BigInt(10 ** token.decimals) >=
144+
BigInt(amount.approveAmount);
145+
if (tokenHasEnoughBalance) {
146+
availableTokens.push({
147+
...token,
148+
approvalAmount: {
149+
approveAmount: amount.approveAmount,
150+
chainId: token.chainId as Hex,
151+
paymentAddress: amount.paymentAddress,
152+
paymentTokenAddress: amount.paymentTokenAddress,
153+
},
154+
type: token.isNative ? AssetType.native : AssetType.token,
155+
} as TokenWithApprovalAmount);
156+
}
157+
});
160158

161-
getAvailableTokenBalances();
162-
}, [price, productType, paymentChainTokenMap, validTokenBalances]);
159+
return availableTokens;
160+
}, [price, paymentChainTokenMap, validTokenBalances]);
163161

164-
return availableTokenBalances;
162+
return {
163+
availableTokenBalances: availableTokenBalances ?? [],
164+
pending,
165+
error,
166+
};
165167
};
166168

167169
/**

ui/pages/shield-plan/shield-plan.tsx

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,12 @@ const ShieldPlan = () => {
135135
return pricingPlans?.find((plan) => plan.interval === selectedPlan);
136136
}, [pricingPlans, selectedPlan]);
137137

138-
const availableTokenBalances = useAvailableTokenBalances({
139-
paymentChains: cryptoPaymentMethod?.chains,
140-
price: selectedProductPrice,
141-
productType: PRODUCT_TYPES.SHIELD,
142-
});
138+
const { availableTokenBalances, pending: pendingAvailableTokenBalances } =
139+
useAvailableTokenBalances({
140+
paymentChains: cryptoPaymentMethod?.chains,
141+
price: selectedProductPrice,
142+
productType: PRODUCT_TYPES.SHIELD,
143+
});
143144
const hasAvailableToken = availableTokenBalances.length > 0;
144145

145146
const [selectedPaymentMethod, setSelectedPaymentMethod] =
@@ -165,17 +166,23 @@ const ShieldPlan = () => {
165166

166167
// set selected token to the first available token if no token is selected
167168
useEffect(() => {
168-
if (selectedToken || availableTokenBalances.length === 0) {
169+
if (
170+
pendingAvailableTokenBalances ||
171+
selectedToken ||
172+
availableTokenBalances.length === 0
173+
) {
169174
return;
170175
}
171176

172177
const lastUsedPaymentToken = lastUsedPaymentDetails?.paymentTokenAddress;
173178
const lastUsedPaymentMethod = lastUsedPaymentDetails?.type;
179+
const lastUsedPaymentPlan = lastUsedPaymentDetails?.plan;
174180

175181
let lastUsedSelectedToken = availableTokenBalances[0];
176182
if (
177183
lastUsedPaymentToken &&
178-
lastUsedPaymentMethod === PAYMENT_TYPES.byCrypto
184+
lastUsedPaymentMethod === PAYMENT_TYPES.byCrypto &&
185+
lastUsedPaymentPlan === selectedPlan
179186
) {
180187
lastUsedSelectedToken =
181188
availableTokenBalances.find(
@@ -185,12 +192,19 @@ const ShieldPlan = () => {
185192

186193
setSelectedToken(lastUsedSelectedToken);
187194
}, [
195+
pendingAvailableTokenBalances,
188196
availableTokenBalances,
189197
selectedToken,
190198
setSelectedToken,
191199
lastUsedPaymentDetails,
200+
selectedPlan,
192201
]);
193202

203+
// reset selected token if selected plan changes
204+
useEffect(() => {
205+
setSelectedToken(undefined);
206+
}, [selectedPlan, setSelectedToken]);
207+
194208
// set default selected payment method to crypto if selected token available
195209
useEffect(() => {
196210
if (selectedToken) {

0 commit comments

Comments
 (0)