-
Notifications
You must be signed in to change notification settings - Fork 367
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add withdrawal L1 fee info modal (#138)
* add withdrawal fee info * cleanup * small updates
- Loading branch information
1 parent
6721126
commit a4b1470
Showing
5 changed files
with
263 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import Image from 'next/image'; | ||
|
||
type TooltipProps = { | ||
children: string; | ||
}; | ||
|
||
export function Tooltip({ children }: TooltipProps) { | ||
return ( | ||
<div className="has-tooltip"> | ||
<span className="tooltip -mt-10 ml-6 max-w-sm rounded-lg bg-cds-background-gray-90 p-2 text-black shadow-lg"> | ||
{children} | ||
</span> | ||
<Image alt="tooltip" src="/icons/question-mark-circled.svg" width={16} height={16} /> | ||
</div> | ||
); | ||
} |
132 changes: 132 additions & 0 deletions
132
apps/bridge/src/components/WithdrawContainer/TransactionSummaryModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { Modal } from 'apps/bridge/src/components/Modal/Modal'; | ||
import { Asset, BridgeProtocol } from 'apps/bridge/src/types/Asset'; | ||
import { usdFormatter } from 'apps/bridge/src/utils/formatter/balance'; | ||
import { useConversionRate } from 'apps/bridge/src/utils/hooks/useConversionRate'; | ||
import { useGetWithdrawalFeeEstimates } from 'apps/bridge/src/utils/hooks/useGetWithdrawalFeeEstimates'; | ||
import { Tooltip } from 'apps/bridge/src/components/Tooltip/Tooltip'; | ||
|
||
const chainIdToNetwork: Record<number, string> = { | ||
1: 'Ethereum Mainnet', | ||
5: 'Goerli Testnet', | ||
11155111: 'Sepolia Testnet', | ||
}; | ||
|
||
const chainIdToTransferTime: Record<number, string> = { | ||
1: 'About 7 days', | ||
5: 'A few minutes', | ||
11155111: 'A few minutes', | ||
}; | ||
|
||
type TransactionSummaryModalProps = { | ||
selectedAsset: Asset; | ||
amount: string; | ||
isOpen: boolean; | ||
onClose: () => void; | ||
onProceed: () => void; | ||
protocol: BridgeProtocol; | ||
}; | ||
|
||
export function TransactionSummaryModal({ | ||
selectedAsset, | ||
amount, | ||
isOpen, | ||
onClose, | ||
onProceed, | ||
protocol, | ||
}: TransactionSummaryModalProps) { | ||
const { eth: feesInETH, usd: feesInUSD } = useGetWithdrawalFeeEstimates({ selectedAsset }); | ||
const assetConversionRate = useConversionRate({ asset: selectedAsset.apiId }); | ||
const fiatAmount = usdFormatter(parseFloat(amount) * (assetConversionRate ?? 0)); | ||
|
||
const proveTooltipText = | ||
'In order to complete a withdrawal, you must submit two additional L1 transactions, each of which requires enough ETH to pay for L1 gas fees charged by the Ethereum network.'; | ||
const finalizeTooltipText = | ||
selectedAsset.protocol === 'CCTP' | ||
? 'In order to complete a withdrawal, you must submit an additional L1 transaction which requires enough ETH to pay for L1 gas fees charged by the Ethereum network.' | ||
: 'In order to complete a withdrawal, you must submit two additional L1 transactions, each of which requires enough ETH to pay for L1 gas fees charged by the Ethereum network.'; | ||
|
||
const content = ( | ||
<div className="flex w-96 flex-col space-y-4"> | ||
<div className="flex w-full flex-row items-center justify-between pt-8"> | ||
<div className="flex flex-col items-start"> | ||
<span className="text-white">Receive {selectedAsset.L1symbol}</span> | ||
<span>On {chainIdToNetwork[selectedAsset.L1chainId]}</span> | ||
</div> | ||
<div className="flex flex-col items-end"> | ||
<span className="text-white"> | ||
{amount} {selectedAsset.L1symbol} | ||
</span> | ||
<span>{fiatAmount}</span> | ||
</div> | ||
</div> | ||
<div className="flex w-full flex-row items-center justify-between pt-8"> | ||
<div className="flex flex-col items-start"> | ||
<span className="text-white">Transfer time</span> | ||
</div> | ||
<div className="flex flex-col items-end"> | ||
<span className="text-white"> | ||
{selectedAsset.protocol === 'CCTP' | ||
? 'A few minutes' | ||
: chainIdToTransferTime[selectedAsset.L1chainId]} | ||
</span> | ||
</div> | ||
</div> | ||
{protocol === 'OP' && ( | ||
<div className="flex w-full flex-row items-center justify-between pt-8"> | ||
<div className="flex flex-row items-center space-x-2"> | ||
<span className="text-white">Verification fee (est.)</span> | ||
<Tooltip>{proveTooltipText}</Tooltip> | ||
</div> | ||
<div className="flex flex-col items-end"> | ||
<span className="text-white">{feesInETH.prove} ETH</span> | ||
<span>{feesInUSD.prove}</span> | ||
</div> | ||
</div> | ||
)} | ||
<div className="flex w-full flex-row items-center justify-between pt-8"> | ||
<div className="flex flex-row items-center space-x-2"> | ||
<span className="text-white">Completion fee (est.)</span> | ||
<Tooltip>{finalizeTooltipText}</Tooltip> | ||
</div> | ||
<div className="flex flex-col items-end"> | ||
<span className="text-white">{feesInETH.finalize} ETH</span> | ||
<span>{feesInUSD.finalize}</span> | ||
</div> | ||
</div> | ||
<div className="flex w-full flex-row items-center justify-between pt-8"> | ||
<div className="flex flex-col items-start"> | ||
<span className="text-white">Fee total (est.)</span> | ||
</div> | ||
<div className="flex flex-col items-end"> | ||
<span className="text-white">{feesInETH.total} ETH</span> | ||
<span>{feesInUSD.total}</span> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
|
||
const footer = ( | ||
<div className="flex flex-row justify-center space-x-12"> | ||
<button | ||
className="w-48 border border-white bg-black py-2 text-lg text-white" | ||
type="button" | ||
onClick={onClose} | ||
> | ||
Cancel | ||
</button> | ||
<button className="w-48 bg-white py-2 text-lg text-black" type="button" onClick={onProceed}> | ||
Continue | ||
</button> | ||
</div> | ||
); | ||
|
||
return ( | ||
<Modal | ||
isOpen={isOpen} | ||
onClose={onClose} | ||
title="Transaction Summary" | ||
content={content} | ||
footer={footer} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
apps/bridge/src/utils/hooks/useGetWithdrawalFeeEstimates.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Asset } from 'apps/bridge/src/types/Asset'; | ||
import { usdFormatter } from 'apps/bridge/src/utils/formatter/balance'; | ||
import { useConversionRate } from 'apps/bridge/src/utils/hooks/useConversionRate'; | ||
import { formatEther } from 'viem'; | ||
import { useFeeData } from 'wagmi'; | ||
|
||
// prove: ~300_000 | ||
// finalize: ~100_000 for ETH, ~215_000 for ERC20, ~170_000 for CCTP | ||
const OP_PROVE_GAS = 300000n; | ||
const OP_FINALIZE_ETH_GAS = 100000n; | ||
const OP_FINALIZE_ERC20_GAS = 215000n; | ||
const CCTP_FINALIZE_GAS = 170000n; | ||
|
||
type UseGetWithdrawalFeeEstimatesProps = { | ||
selectedAsset: Asset; | ||
}; | ||
|
||
export function useGetWithdrawalFeeEstimates({ selectedAsset }: UseGetWithdrawalFeeEstimatesProps) { | ||
const { data: feeData } = useFeeData({ chainId: selectedAsset.L1chainId }); | ||
const ethConversionRate = useConversionRate({ asset: 'ethereum', refetch: false }); | ||
|
||
const proveGas = selectedAsset.protocol === 'CCTP' ? 0n : OP_PROVE_GAS; | ||
let finalizeGas; | ||
if (selectedAsset.protocol === 'CCTP') { | ||
finalizeGas = CCTP_FINALIZE_GAS; | ||
} else { | ||
finalizeGas = selectedAsset.L2symbol === 'ETH' ? OP_FINALIZE_ETH_GAS : OP_FINALIZE_ERC20_GAS; | ||
} | ||
|
||
const proveEstimate = parseFloat(formatEther((feeData?.gasPrice ?? 0n) * proveGas)); | ||
const finalizeEstimate = parseFloat(formatEther((feeData?.gasPrice ?? 0n) * finalizeGas)); | ||
|
||
const proveEstimateFormatted = proveEstimate * (ethConversionRate ?? 0); | ||
const finalizeEstimateFormatted = finalizeEstimate * (ethConversionRate ?? 0); | ||
|
||
const fees = { | ||
eth: { | ||
prove: proveEstimate.toFixed(4), | ||
finalize: finalizeEstimate.toFixed(4), | ||
total: (proveEstimate + finalizeEstimate).toFixed(4), | ||
}, | ||
usd: { | ||
prove: usdFormatter(proveEstimateFormatted), | ||
finalize: usdFormatter(finalizeEstimateFormatted), | ||
total: usdFormatter(proveEstimateFormatted + finalizeEstimateFormatted), | ||
}, | ||
}; | ||
|
||
return fees; | ||
} |