Skip to content

Commit d91a46d

Browse files
authored
Fix teth balance on redeem (#218)
1 parent 15fbacf commit d91a46d

File tree

4 files changed

+4177
-2128
lines changed

4 files changed

+4177
-2128
lines changed

app/mint-teth/components/Redeem.tsx

Lines changed: 32 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import { useWalletClient, useWallets } from "@/app/hooks";
2-
import {
3-
DynamicConnectButton,
4-
useDynamicContext,
5-
} from "@dynamic-labs/sdk-react-core";
2+
import { DynamicConnectButton, useDynamicContext } from "@dynamic-labs/sdk-react-core";
63
import classNames from "classnames";
74
import { useEffect, useMemo, useState } from "react";
85
import {
@@ -69,58 +66,42 @@ export function Redeem() {
6966
///////////////////////
7067
// State
7168
///////////////////////
72-
const [walletClient, setWalletClient] = useState<WalletClient<
73-
Transport,
74-
Chain,
75-
Account
76-
> | null>(null);
69+
const [walletClient, setWalletClient] = useState<WalletClient<Transport, Chain, Account> | null>(null);
7770
const [redeemAmount, setRedeemAmount] = useState<string>("");
7871
const [receiveAsset, setReceiveAsset] = useState<string>(tokenAddresses[0]);
7972
const [assetPerTethRate, setAssetPerTethRate] = useState<string>("");
8073
const [ethPerAssetRate, setEthPerAssetRate] = useState("");
8174
const [ethPerTethRate, setEthPerTethRate] = useState("");
8275
const [depositPending, setDepositPending] = useState<boolean>(false);
83-
const [tokenBalanceAsBigInt, setTokenBalanceAsBigInt] = useState<bigint>(
84-
BigInt(1),
85-
);
76+
const [tokenBalanceAsBigInt, setTokenBalanceAsBigInt] = useState<bigint>(BigInt(1));
8677
const [isLoadingTokenBalance, setIsLoadingTokenBalance] = useState(false);
8778
const [isModalOpen, setIsModalOpen] = useState(false);
8879
const [currentTx, setCurrentTx] = useState<any>(null);
8980
const [depositTxHash, setDepositTxHash] = useState<string>("");
9081
const [tethBalance, setTethBalance] = useState<string>("");
9182
const [tethBalanceLoading, setTethBalanceLoading] = useState(false);
9283
const [ethPrice, setEthPrice] = useState<string>("");
93-
const [sourceChain, setSourceChain] = useState<SelectOption | undefined>(
94-
chainOptions[0],
95-
);
84+
const [sourceChain, setSourceChain] = useState<SelectOption | undefined>(chainOptions[0]);
9685

9786
///////////////////////
9887
// Derived values
9988
///////////////////////
10089
const publicClient = createPublicClient({
10190
chain: mainnet,
102-
transport: http(
103-
"https://empty-responsive-patron.quiknode.pro/91dfa8475605dcdec9afdc8273578c9f349774a1/",
104-
),
91+
transport: http("https://empty-responsive-patron.quiknode.pro/91dfa8475605dcdec9afdc8273578c9f349774a1/"),
10592
cacheTime: 0,
10693
});
10794

108-
const atomicPrice =
109-
(BigInt(assetPerTethRate) *
110-
(BigInt(1e18) - parseUnits(slippage.toString(), 18))) /
111-
BigInt(1e18);
95+
const atomicPrice = (BigInt(assetPerTethRate) * (BigInt(1e18) - parseUnits(slippage.toString(), 18))) / BigInt(1e18);
11296

11397
const formattedTokenBalance = formatUnits(BigInt(tethBalance), 18);
11498
const atomicPriceAsBigInt = BigInt(atomicPrice);
11599
const redeemAmountAsBigInt = BigInt(parseUnits(redeemAmount, 18));
116100

117101
// Withdraw fee
118-
const withdrawFeeInTeth =
119-
(redeemAmountAsBigInt * parseUnits(slippage.toString(), 18)) / BigInt(1e18);
120-
const withdrawFeeInEth =
121-
(withdrawFeeInTeth * BigInt(ethPerTethRate)) / BigInt(1e18);
122-
const withdrawFeeInUsdAsBigInt =
123-
(withdrawFeeInEth * BigInt(ethPrice)) / BigInt(1e8);
102+
const withdrawFeeInTeth = (redeemAmountAsBigInt * parseUnits(slippage.toString(), 18)) / BigInt(1e18);
103+
const withdrawFeeInEth = (withdrawFeeInTeth * BigInt(ethPerTethRate)) / BigInt(1e18);
104+
const withdrawFeeInUsdAsBigInt = (withdrawFeeInEth * BigInt(ethPrice)) / BigInt(1e8);
124105
const withdrawFeeInUsd = Number(formatUnits(withdrawFeeInUsdAsBigInt, 18));
125106
const formattedWithdrawFeeInUsd =
126107
withdrawFeeInUsd > 0 && withdrawFeeInUsd < 0.01
@@ -131,8 +112,7 @@ export function Redeem() {
131112
}).format(withdrawFeeInUsd)}`;
132113

133114
// Bridge fee
134-
const bridgeFeeInUsdAsBigInt =
135-
(interchainTransferFee * BigInt(ethPrice)) / BigInt(1e8);
115+
const bridgeFeeInUsdAsBigInt = (interchainTransferFee * BigInt(ethPrice)) / BigInt(1e8);
136116
const bridgeFeeInUsd = Number(formatUnits(bridgeFeeInUsdAsBigInt, 18));
137117
const formattedBridgeFeeInUsd =
138118
bridgeFeeInUsd > 0 && bridgeFeeInUsd < 0.01
@@ -144,8 +124,7 @@ export function Redeem() {
144124

145125
// Total fees
146126
const totalFeesInEth = withdrawFeeInEth + interchainTransferFee;
147-
const totalFeesInUsdAsBigInt =
148-
(totalFeesInEth * BigInt(ethPrice)) / BigInt(1e8);
127+
const totalFeesInUsdAsBigInt = (totalFeesInEth * BigInt(ethPrice)) / BigInt(1e8);
149128
const totalFeesInUsd = Number(formatUnits(totalFeesInUsdAsBigInt, 18));
150129
const formattedTotalFeesInUsd =
151130
totalFeesInUsd > 0 && totalFeesInUsd < 0.01
@@ -158,23 +137,16 @@ export function Redeem() {
158137
const isOverBalance = BigInt(tethBalance) < redeemAmountAsBigInt;
159138

160139
const isMintDisabled =
161-
depositPending ||
162-
!redeemAmount ||
163-
!receiveAsset ||
164-
!evmWallet ||
165-
isOverBalance ||
166-
Number(redeemAmount) === 0;
140+
depositPending || !redeemAmount || !receiveAsset || !evmWallet || isOverBalance || Number(redeemAmount) === 0;
167141

168142
const evmAddress = evmWallet?.address as `0x${string}` | undefined;
169143
const svmAddress = solWallet?.address as `0x${string}` | undefined;
170144

171145
const ethPriceAsBigInt = ethPrice ? BigInt(ethPrice) : BigInt(0);
172146

173147
// Redeem amount
174-
const redeemAmountInEth =
175-
(redeemAmountAsBigInt * BigInt(ethPerTethRate)) / BigInt(1e18);
176-
const redeemAmountInUsd =
177-
(redeemAmountInEth * ethPriceAsBigInt) / BigInt(1e8);
148+
const redeemAmountInEth = (redeemAmountAsBigInt * BigInt(ethPerTethRate)) / BigInt(1e18);
149+
const redeemAmountInUsd = (redeemAmountInEth * ethPriceAsBigInt) / BigInt(1e8);
178150
const redeemAmountInUsdFormatted = Number(formatUnits(redeemAmountInUsd, 18));
179151
const formattedRedeemAmountInUsd =
180152
redeemAmountInUsdFormatted > 0 && redeemAmountInUsdFormatted < 0.01
@@ -195,11 +167,8 @@ export function Redeem() {
195167
? (receiveAmountAsBigInt * BigInt(ethPerAssetRate)) / BigInt(1e18)
196168
: BigInt(0);
197169

198-
const receiveAmountInUsd =
199-
(receiveAmountInEth * ethPriceAsBigInt) / BigInt(1e8);
200-
const receiveAmountInUsdFormatted = Number(
201-
formatUnits(receiveAmountInUsd, 18),
202-
);
170+
const receiveAmountInUsd = (receiveAmountInEth * ethPriceAsBigInt) / BigInt(1e8);
171+
const receiveAmountInUsdFormatted = Number(formatUnits(receiveAmountInUsd, 18));
203172
const formattedReceiveAmountInUsd =
204173
receiveAmountInUsdFormatted > 0 && receiveAmountInUsdFormatted < 0.01
205174
? "<$0.01"
@@ -210,9 +179,7 @@ export function Redeem() {
210179

211180
// Memoized because it iterates over an array
212181
const { depositAssetLabel, depositAssetIcon } = useMemo(() => {
213-
const tokenOption = tokenOptions.find(
214-
(token) => token.value === receiveAsset,
215-
);
182+
const tokenOption = tokenOptions.find((token) => token.value === receiveAsset);
216183
return {
217184
depositAssetLabel: tokenOption?.label,
218185
depositAssetIcon: tokenOption?.imageSrc,
@@ -236,12 +203,7 @@ export function Redeem() {
236203
link: `https://etherscan.io/tx/${depositTxHash}`,
237204
},
238205
];
239-
}, [
240-
atomicRequestApprovalState,
241-
atomicRequestState,
242-
depositTxHash,
243-
tokenTransferState,
244-
]);
206+
}, [atomicRequestApprovalState, atomicRequestState, depositTxHash, tokenTransferState]);
245207

246208
///////////////////////
247209
// Use effects
@@ -250,9 +212,7 @@ export function Redeem() {
250212
useEffect(() => {
251213
let lWalletClient =
252214
//@ts-ignore
253-
evmWallet?.connector.getWalletClient<
254-
WalletClient<Transport, Chain, Account>
255-
>();
215+
evmWallet?.connector.getWalletClient<WalletClient<Transport, Chain, Account>>();
256216
lWalletClient && (lWalletClient.cacheTime = 0);
257217
setWalletClient(lWalletClient ?? null);
258218
}, [evmWallet?.connector]);
@@ -262,20 +222,10 @@ export function Redeem() {
262222
async function getSvmBalance() {
263223
try {
264224
setTethBalanceLoading(true);
265-
if (tethBalance != "") {
266-
return;
267-
}
268225
if (sourceChain?.value === "eclipse" && svmAddress) {
269-
const balance = await getSolanaBalance(
270-
svmAddress,
271-
tethSvmTokenAddress,
272-
);
226+
const balance = await getSolanaBalance(svmAddress, tethSvmTokenAddress);
273227
setTethBalance(balance.toString());
274-
} else if (
275-
sourceChain?.value === "ethereum" &&
276-
evmAddress &&
277-
publicClient
278-
) {
228+
} else if (sourceChain?.value === "ethereum" && evmAddress && publicClient) {
279229
const balance = await balanceOf({
280230
tokenAddress: tethEvmTokenAddress,
281231
userAddress: evmAddress,
@@ -311,14 +261,11 @@ export function Redeem() {
311261
if (asset === "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2") {
312262
_ethPerAssetRate = BigInt(1e18);
313263
} else {
314-
_ethPerAssetRate = await getRate(
315-
{ tokenAddress: asset },
316-
{ publicClient },
317-
);
264+
_ethPerAssetRate = await getRate({ tokenAddress: asset }, { publicClient });
318265
}
319266
const _ethPerTethRate = await getRateInQuote(
320267
{ quote: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" }, // WETH
321-
{ publicClient },
268+
{ publicClient }
322269
);
323270
const _ethPrice = await latestRoundData({ publicClient });
324271

@@ -348,8 +295,7 @@ export function Redeem() {
348295
useEffect(() => {
349296
async function getTokenBalance() {
350297
try {
351-
if (!publicClient || !evmWallet || tokenBalanceAsBigInt != BigInt(1))
352-
return;
298+
if (!publicClient || !evmWallet || tokenBalanceAsBigInt != BigInt(1)) return;
353299
setIsLoadingTokenBalance(true);
354300
const _tokenBalanceAsBigInt = await balanceOf({
355301
tokenAddress: receiveAsset as `0x${string}`,
@@ -408,9 +354,7 @@ export function Redeem() {
408354
setIsModalOpen(true);
409355

410356
// Make the swap (this step takes up to 24 hours)
411-
const deadlineInSec = BigInt(
412-
Math.floor(Date.now() / 1000) + deadlineDaysFromNow * 24 * 60 * 60,
413-
);
357+
const deadlineInSec = BigInt(Math.floor(Date.now() / 1000) + deadlineDaysFromNow * 24 * 60 * 60);
414358
const offerAmount = parseUnits(redeemAmount, 18);
415359

416360
if (!evmAddress) throw new Error("No EVM address found");
@@ -443,15 +387,10 @@ export function Redeem() {
443387
offerAddress: tethEvmTokenAddress,
444388
wantAddress: receiveAsset as `0x${string}`,
445389
},
446-
{ publicClient },
390+
{ publicClient }
447391
);
448-
const {
449-
atomicPrice: pendingAtomicPrice,
450-
offerAmount: pendingOfferAmount,
451-
} = pendingAtomicRequest;
452-
const atomicRequestAlreadyExists =
453-
pendingAtomicPrice === atomicPrice &&
454-
pendingOfferAmount === offerAmount;
392+
const { atomicPrice: pendingAtomicPrice, offerAmount: pendingOfferAmount } = pendingAtomicRequest;
393+
const atomicRequestAlreadyExists = pendingAtomicPrice === atomicPrice && pendingOfferAmount === offerAmount;
455394

456395
if (!atomicRequestAlreadyExists) {
457396
const txHash = await updateAtomicRequest(
@@ -465,7 +404,7 @@ export function Redeem() {
465404
inSolve: false,
466405
},
467406
},
468-
{ publicClient, walletClient },
407+
{ publicClient, walletClient }
469408
);
470409
} else {
471410
setAtomicRequestState(StepStatus.LOADING);
@@ -482,11 +421,7 @@ export function Redeem() {
482421

483422
return (
484423
<>
485-
<div
486-
className={
487-
isModalOpen ? "mint-status-overlay active" : "mint-status-overlay"
488-
}
489-
></div>
424+
<div className={isModalOpen ? "mint-status-overlay active" : "mint-status-overlay"}></div>
490425
{isModalOpen && (
491426
<MintTransactionDetails
492427
fromDeposit={true}
@@ -532,9 +467,7 @@ export function Redeem() {
532467
userAddress={evmAddress}
533468
inputValue={formattedReceiveAmount}
534469
disabled={true}
535-
depositAsset={tokenOptions.find(
536-
(token) => token.value === receiveAsset,
537-
)}
470+
depositAsset={tokenOptions.find((token) => token.value === receiveAsset)}
538471
tokenBalance={tokenBalanceAsBigInt}
539472
usdValue={formattedReceiveAmountInUsd}
540473
handleDisconnect={() => evmWallet && handleUnlinkWallet(evmWallet.id)}
@@ -568,12 +501,7 @@ export function Redeem() {
568501
buttonClassName="wallet-connect-button w-full"
569502
buttonContainerClassName="submit-button connect-btn"
570503
>
571-
<span style={{ width: "100%" }}>
572-
{" "}
573-
{!evmAddress && !svmAddress
574-
? "Connect Wallets"
575-
: "Connect Wallet"}
576-
</span>
504+
<span style={{ width: "100%" }}> {!evmAddress && !svmAddress ? "Connect Wallets" : "Connect Wallet"}</span>
577505
</DynamicConnectButton>
578506
)}
579507
</div>

app/mint-teth/hooks/useTokenTransfer.ts

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,18 @@ import { warpCore } from "../lib/warpcore";
77
import { StepStatus } from "../types";
88

99
export function useTokenTransfer() {
10-
const [transactionState, setTransactionState] = useState<StepStatus>(
11-
StepStatus.NOT_STARTED,
12-
);
10+
const [transactionState, setTransactionState] = useState<StepStatus>(StepStatus.NOT_STARTED);
1311
const [error, setError] = useState<string | null>(null);
1412
const { evmWallet, solWallet } = useWallets();
15-
const [interchainTransferFee, setInterchainTransferFee] = useState<bigint>(
16-
BigInt(0),
17-
);
13+
const [interchainTransferFee, setInterchainTransferFee] = useState<bigint>(BigInt(0));
1814

1915
useEffect(() => {
2016
async function fetchFee() {
2117
try {
2218
const originToken = warpCore.tokens.find(
23-
(token) =>
24-
token.chainName === "eclipsemainnet" && token.symbol === "tETH",
19+
(token) => token.chainName === "eclipsemainnet" && token.symbol === "tETH"
2520
);
26-
if (!originToken) {
21+
if (!originToken || !solWallet?.address) {
2722
return;
2823
}
2924
const fee = await warpCore.getInterchainTransferFee({
@@ -48,9 +43,7 @@ export function useTokenTransfer() {
4843

4944
setTransactionState(StepStatus.AWAITING_SIGNATURE);
5045
try {
51-
const connection = new Connection(
52-
process.env.NEXT_PUBLIC_ECLIPSE_RPC || "",
53-
);
46+
const connection = new Connection(process.env.NEXT_PUBLIC_ECLIPSE_RPC || "");
5447

5548
// Define paramaters
5649
const destination = "ethereum";
@@ -79,16 +72,12 @@ export function useTokenTransfer() {
7972
for (const tx of txs) {
8073
if (tx.type === ProviderType.SolanaWeb3) {
8174
// Sign and send Solana transaction
82-
const signer = await (
83-
solWallet?.connector as SolanaWalletConnector
84-
).getSigner();
75+
const signer = await (solWallet?.connector as SolanaWalletConnector).getSigner();
8576
if (!signer) {
8677
return 1;
8778
}
8879
const signedTx = await signer.signTransaction(tx.transaction);
89-
const txId = await connection.sendRawTransaction(
90-
signedTx.serialize(),
91-
);
80+
const txId = await connection.sendRawTransaction(signedTx.serialize());
9281
await connection.confirmTransaction(txId, "confirmed");
9382
}
9483
}
@@ -102,7 +91,7 @@ export function useTokenTransfer() {
10291
throw e;
10392
}
10493
},
105-
[evmWallet, solWallet],
94+
[evmWallet, solWallet]
10695
);
10796

10897
return {

0 commit comments

Comments
 (0)