2022-08-17 13:06:25 -07:00
import React , {
Dispatch ,
SetStateAction ,
2022-12-19 10:48:59 -08:00
useCallback ,
2022-08-17 13:06:25 -07:00
useEffect ,
useMemo ,
useState ,
} from 'react'
2022-12-14 18:51:21 -08:00
import {
TransactionInstruction ,
PublicKey ,
VersionedTransaction ,
Connection ,
2022-12-15 14:51:19 -08:00
TransactionMessage ,
AddressLookupTableAccount ,
2022-12-14 18:51:21 -08:00
} from '@solana/web3.js'
2022-08-17 13:06:25 -07:00
import Decimal from 'decimal.js'
2022-09-12 08:53:57 -07:00
import mangoStore from '@store/mangoStore'
2022-08-17 13:06:25 -07:00
import Button , { IconButton } from '../shared/Button'
import Loading from '../shared/Loading'
import {
ArrowLeftIcon ,
PencilIcon ,
2022-09-06 21:36:35 -07:00
ArrowsRightLeftIcon ,
2022-09-16 04:37:24 -07:00
ArrowRightIcon ,
2022-12-28 20:17:38 -08:00
ChevronDownIcon ,
2022-09-06 21:36:35 -07:00
} from '@heroicons/react/20/solid'
2022-08-17 13:06:25 -07:00
import { useTranslation } from 'next-i18next'
2022-10-28 14:46:38 -07:00
import Image from 'next/legacy/image'
2022-12-16 14:12:07 -08:00
import { formatDecimal , formatFixedDecimals } from '../../utils/numbers'
2022-08-19 21:03:26 -07:00
import { notify } from '../../utils/notifications'
2022-11-18 11:11:06 -08:00
import useJupiterMints from '../../hooks/useJupiterMints'
2022-11-18 20:59:06 -08:00
import { RouteInfo } from 'types/jupiter'
2022-11-18 11:11:06 -08:00
import useJupiterSwapData from './useJupiterSwapData'
2022-12-14 18:51:21 -08:00
// import { Transaction } from '@solana/web3.js'
2022-12-16 09:30:39 -08:00
import { SOUND_SETTINGS_KEY } from 'utils/constants'
2022-11-22 21:38:31 -08:00
import useLocalStorageState from 'hooks/useLocalStorageState'
2022-11-23 04:40:38 -08:00
import { Howl } from 'howler'
2022-11-24 18:39:14 -08:00
import { INITIAL_SOUND_SETTINGS } from '@components/settings/SoundSettings'
2022-12-08 15:42:55 -08:00
import Tooltip from '@components/shared/Tooltip'
2022-12-28 20:17:38 -08:00
import { Disclosure } from '@headlessui/react'
2022-12-29 02:59:56 -08:00
import RoutesModal from './RoutesModal'
2022-08-17 13:06:25 -07:00
type JupiterRouteInfoProps = {
2022-08-17 18:26:38 -07:00
amountIn : Decimal
2022-08-18 13:50:34 -07:00
onClose : ( ) = > void
routes : RouteInfo [ ] | undefined
2022-08-17 13:06:25 -07:00
selectedRoute : RouteInfo | undefined
setSelectedRoute : Dispatch < SetStateAction < RouteInfo | undefined > >
2022-08-18 13:50:34 -07:00
slippage : number
2022-08-17 13:06:25 -07:00
}
2022-12-15 14:51:19 -08:00
const deserializeJupiterIxAndAlt = async (
connection : Connection ,
swapTransaction : string
) : Promise < [ TransactionInstruction [ ] , AddressLookupTableAccount [ ] ] > = > {
const parsedSwapTransaction = VersionedTransaction . deserialize (
Buffer . from ( swapTransaction , 'base64' )
)
const message = parsedSwapTransaction . message
2022-12-15 15:00:47 -08:00
// const lookups = message.addressTableLookups
2022-12-15 14:51:19 -08:00
const addressLookupTablesResponses = await Promise . all (
message . addressTableLookups . map ( ( alt ) = >
connection . getAddressLookupTable ( alt . accountKey )
)
)
const addressLookupTables : AddressLookupTableAccount [ ] =
addressLookupTablesResponses
. map ( ( alt ) = > alt . value )
. filter ( ( x ) : x is AddressLookupTableAccount = > x !== null )
const decompiledMessage = TransactionMessage . decompile ( message , {
addressLookupTableAccounts : addressLookupTables ,
} )
2022-12-15 15:00:47 -08:00
return [ decompiledMessage . instructions , addressLookupTables ]
2022-12-15 14:51:19 -08:00
}
const fetchJupiterTransaction = async (
2022-12-14 18:51:21 -08:00
connection : Connection ,
2022-08-17 13:06:25 -07:00
selectedRoute : RouteInfo ,
2022-11-18 20:59:06 -08:00
userPublicKey : PublicKey ,
2022-12-16 14:49:03 -08:00
slippage : number ,
2022-12-26 09:14:34 -08:00
inputMint : PublicKey ,
outputMint : PublicKey
2022-12-15 14:51:19 -08:00
) : Promise < [ TransactionInstruction [ ] , AddressLookupTableAccount [ ] ] > = > {
2022-11-18 11:11:06 -08:00
const transactions = await (
2022-12-14 18:51:21 -08:00
await fetch ( 'https://quote-api.jup.ag/v4/swap' , {
2022-11-18 11:11:06 -08:00
method : 'POST' ,
headers : {
'Content-Type' : 'application/json' ,
} ,
body : JSON.stringify ( {
// route from /quote api
route : selectedRoute ,
// user public key to be used for the swap
userPublicKey ,
// feeAccount is optional. Use if you want to charge a fee. feeBps must have been passed in /quote API.
// This is the ATA account for the output token where the fee will be sent to. If you are swapping from SOL->USDC then this would be the USDC ATA you want to collect the fee.
2022-11-18 20:59:06 -08:00
// feeAccount: 'fee_account_public_key',
slippageBps : Math.ceil ( slippage * 100 ) ,
2022-11-18 11:11:06 -08:00
} ) ,
} )
) . json ( )
2022-11-18 20:59:06 -08:00
2022-08-17 13:06:25 -07:00
const { swapTransaction } = transactions
2022-11-18 20:59:06 -08:00
2022-12-15 14:51:19 -08:00
const [ ixs , alts ] = await deserializeJupiterIxAndAlt (
connection ,
swapTransaction
)
2022-12-14 18:51:21 -08:00
2022-12-16 09:30:39 -08:00
const isSetupIx = ( pk : PublicKey ) : boolean = >
pk . toString ( ) === 'ComputeBudget111111111111111111111111111111' ||
pk . toString ( ) === 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
2022-12-14 18:51:21 -08:00
2022-12-16 14:49:03 -08:00
const isDuplicateAta = ( ix : TransactionInstruction ) : boolean = > {
return (
ix . programId . toString ( ) ===
'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL' &&
2022-12-26 09:14:34 -08:00
( ix . keys [ 3 ] . pubkey . toString ( ) === inputMint . toString ( ) ||
ix . keys [ 3 ] . pubkey . toString ( ) === outputMint . toString ( ) )
2022-12-16 14:49:03 -08:00
)
}
2022-12-26 09:14:34 -08:00
const filtered_jup_ixs = ixs
. filter ( ( ix ) = > ! isSetupIx ( ix . programId ) )
. filter ( ( ix ) = > ! isDuplicateAta ( ix ) )
2022-12-16 14:49:03 -08:00
console . log ( 'ixs: ' , ixs )
console . log ( 'filtered ixs: ' , filtered_jup_ixs )
2022-12-15 14:51:19 -08:00
return [ filtered_jup_ixs , alts ]
2022-08-17 13:06:25 -07:00
}
2022-08-25 13:24:37 -07:00
const EMPTY_COINGECKO_PRICES = {
inputCoingeckoPrice : 0 ,
outputCoingeckoPrice : 0 ,
}
2022-12-07 21:05:36 -08:00
const successSound = new Howl ( {
src : [ '/sounds/swap-success.mp3' ] ,
volume : 0.5 ,
} )
2022-12-07 13:33:35 -08:00
const SwapReviewRouteInfo = ( {
2022-08-17 13:06:25 -07:00
amountIn ,
onClose ,
routes ,
selectedRoute ,
2022-12-29 02:59:56 -08:00
setSelectedRoute ,
2022-08-17 13:06:25 -07:00
} : JupiterRouteInfoProps ) = > {
2022-08-26 10:17:31 -07:00
const { t } = useTranslation ( [ 'common' , 'trade' ] )
2022-12-28 20:17:38 -08:00
const slippage = mangoStore ( ( s ) = > s . swap . slippage )
2022-12-29 02:59:56 -08:00
const [ showRoutesModal , setShowRoutesModal ] = useState < boolean > ( false )
2022-08-17 13:06:25 -07:00
const [ swapRate , setSwapRate ] = useState < boolean > ( false )
2022-11-19 11:20:36 -08:00
const [ feeValue ] = useState < number | null > ( null )
2022-08-19 21:03:26 -07:00
const [ submitting , setSubmitting ] = useState ( false )
2022-08-25 13:24:37 -07:00
const [ coingeckoPrices , setCoingeckoPrices ] = useState ( EMPTY_COINGECKO_PRICES )
2022-12-15 14:51:19 -08:00
const { jupiterTokens } = useJupiterMints ( )
2022-11-18 11:11:06 -08:00
const { inputTokenInfo , outputTokenInfo } = useJupiterSwapData ( )
2022-09-05 15:38:47 -07:00
const inputBank = mangoStore ( ( s ) = > s . swap . inputBank )
2022-11-22 21:38:31 -08:00
const [ soundSettings ] = useLocalStorageState (
SOUND_SETTINGS_KEY ,
INITIAL_SOUND_SETTINGS
)
2022-08-17 13:06:25 -07:00
const inputTokenIconUri = useMemo ( ( ) = > {
2022-08-18 13:50:34 -07:00
return inputTokenInfo ? inputTokenInfo . logoURI : ''
} , [ inputTokenInfo ] )
2022-08-17 13:06:25 -07:00
const amountOut = useMemo ( ( ) = > {
if ( ! selectedRoute || ! outputTokenInfo ) return
2022-09-02 16:52:07 -07:00
return new Decimal ( selectedRoute . outAmount . toString ( ) ) . div (
10 * * outputTokenInfo . decimals
2022-08-17 13:06:25 -07:00
)
} , [ selectedRoute , outputTokenInfo ] )
2022-08-25 13:24:37 -07:00
useEffect ( ( ) = > {
setCoingeckoPrices ( EMPTY_COINGECKO_PRICES )
const fetchTokenPrices = async ( ) = > {
const inputId = inputTokenInfo ? . extensions ? . coingeckoId
const outputId = outputTokenInfo ? . extensions ? . coingeckoId
if ( inputId && outputId ) {
const results = await fetch (
` https://api.coingecko.com/api/v3/simple/price?ids= ${ inputId } , ${ outputId } &vs_currencies=usd `
)
const json = await results . json ( )
if ( json [ inputId ] ? . usd && json [ outputId ] ? . usd ) {
setCoingeckoPrices ( {
inputCoingeckoPrice : json [ inputId ] . usd ,
outputCoingeckoPrice : json [ outputId ] . usd ,
} )
}
}
}
if ( inputTokenInfo && outputTokenInfo ) {
fetchTokenPrices ( )
}
} , [ inputTokenInfo , outputTokenInfo ] )
2022-12-19 10:48:59 -08:00
const onSwap = useCallback ( async ( ) = > {
2022-11-18 11:11:06 -08:00
if ( ! selectedRoute ) return
2022-08-19 21:03:26 -07:00
try {
const client = mangoStore . getState ( ) . client
const group = mangoStore . getState ( ) . group
const actions = mangoStore . getState ( ) . actions
const mangoAccount = mangoStore . getState ( ) . mangoAccount . current
const inputBank = mangoStore . getState ( ) . swap . inputBank
const outputBank = mangoStore . getState ( ) . swap . outputBank
2022-11-21 19:23:54 -08:00
const set = mangoStore . getState ( ) . set
2022-12-14 18:51:21 -08:00
const connection = mangoStore . getState ( ) . connection
2022-08-19 21:03:26 -07:00
if ( ! mangoAccount || ! group || ! inputBank || ! outputBank ) return
2023-01-02 13:04:58 -08:00
setSubmitting ( true )
2022-12-15 14:51:19 -08:00
const [ ixs , alts ] = await fetchJupiterTransaction (
2022-12-14 18:51:21 -08:00
connection ,
2022-11-18 20:59:06 -08:00
selectedRoute ,
2022-11-19 11:20:36 -08:00
mangoAccount . owner ,
2022-12-16 14:49:03 -08:00
slippage ,
2022-12-26 09:14:34 -08:00
inputBank . mint ,
outputBank . mint
2022-11-18 20:59:06 -08:00
)
2022-08-19 21:03:26 -07:00
try {
const tx = await client . marginTrade ( {
group ,
mangoAccount ,
inputMintPk : inputBank.mint ,
amountIn : amountIn.toNumber ( ) ,
outputMintPk : outputBank.mint ,
userDefinedInstructions : ixs ,
2022-12-15 14:51:19 -08:00
userDefinedAlts : alts ,
2022-08-19 21:03:26 -07:00
flashLoanType : { swap : { } } ,
} )
2022-11-21 19:23:54 -08:00
set ( ( s ) = > {
s . swap . success = true
} )
2022-11-23 04:40:38 -08:00
if ( soundSettings [ 'swap-success' ] ) {
successSound . play ( )
2022-11-22 21:38:31 -08:00
}
2022-08-19 21:03:26 -07:00
notify ( {
title : 'Transaction confirmed' ,
type : 'success' ,
txid : tx ,
2022-11-23 04:40:38 -08:00
noSound : true ,
2022-08-19 21:03:26 -07:00
} )
2022-09-02 16:51:35 -07:00
actions . fetchGroup ( )
2022-12-19 11:42:28 -08:00
actions . fetchSwapHistory ( mangoAccount . publicKey . toString ( ) , 30000 )
2022-08-25 20:30:39 -07:00
await actions . reloadMangoAccount ( )
2022-08-19 21:03:26 -07:00
} catch ( e : any ) {
2022-08-20 17:09:36 -07:00
console . error ( 'onSwap error: ' , e )
2022-08-19 21:03:26 -07:00
notify ( {
title : 'Transaction failed' ,
description : e.message ,
2022-12-02 15:47:08 -08:00
txid : e?.txid ,
2022-08-19 21:03:26 -07:00
type : 'error' ,
} )
} finally {
setSubmitting ( false )
}
} catch ( e ) {
console . error ( 'Swap error:' , e )
} finally {
onClose ( )
}
2022-12-19 10:48:59 -08:00
} , [ amountIn , onClose , selectedRoute , soundSettings ] )
2022-08-17 13:06:25 -07:00
2022-12-08 15:42:55 -08:00
const [ balance , borrowAmount ] = useMemo ( ( ) = > {
2022-08-25 13:24:37 -07:00
const mangoAccount = mangoStore . getState ( ) . mangoAccount . current
const inputBank = mangoStore . getState ( ) . swap . inputBank
2022-12-08 15:42:55 -08:00
if ( ! mangoAccount || ! inputBank ) return [ 0 , 0 ]
2022-12-09 10:16:48 -08:00
2022-12-08 15:42:55 -08:00
const balance = mangoAccount . getTokenDepositsUi ( inputBank )
const remainingBalance = balance - amountIn . toNumber ( )
const borrowAmount = remainingBalance < 0 ? Math . abs ( remainingBalance ) : 0
2022-12-09 10:16:48 -08:00
2022-12-08 15:42:55 -08:00
return [ balance , borrowAmount ]
2022-08-25 13:24:37 -07:00
} , [ amountIn ] )
const coinGeckoPriceDifference = useMemo ( ( ) = > {
2022-12-09 10:16:48 -08:00
return amountOut ? . toNumber ( )
2022-12-16 14:12:07 -08:00
? amountIn
. div ( amountOut )
. minus (
new Decimal ( coingeckoPrices ? . outputCoingeckoPrice ) . div (
coingeckoPrices ? . inputCoingeckoPrice
2022-09-02 11:36:57 -07:00
)
2022-12-16 14:12:07 -08:00
)
. div ( amountIn . div ( amountOut ) )
. mul ( 100 )
2022-09-02 11:36:57 -07:00
: new Decimal ( 0 )
2022-08-25 13:24:37 -07:00
} , [ coingeckoPrices , amountIn , amountOut ] )
2022-08-17 13:06:25 -07:00
return routes ? . length && selectedRoute && outputTokenInfo && amountOut ? (
2022-12-28 20:17:38 -08:00
< div className = "thin-scroll flex h-full flex-col justify-between overflow-y-auto" >
2022-08-17 13:06:25 -07:00
< div >
< IconButton
2022-12-19 03:20:01 -08:00
className = "absolute top-4 left-4 mr-3 text-th-fgd-2"
2022-08-17 13:06:25 -07:00
onClick = { onClose }
size = "small"
>
< ArrowLeftIcon className = "h-5 w-5" / >
< / IconButton >
2022-12-19 03:20:01 -08:00
< div className = "flex justify-center bg-gradient-to-t from-th-bkg-1 to-th-bkg-2 p-6 pb-0" >
< div className = "mb-4 flex w-full flex-col items-center border-b border-th-bkg-3 pb-4" >
2022-08-17 13:06:25 -07:00
< div className = "relative mb-2 w-[72px]" >
< Image alt = "" width = "40" height = "40" src = { inputTokenIconUri } / >
< div className = "absolute right-0 top-0" >
< Image
className = "drop-shadow-md"
alt = ""
width = "40"
height = "40"
src = { outputTokenInfo . logoURI }
/ >
< / div >
< / div >
2022-09-16 04:37:24 -07:00
< p className = "mb-0.5 flex items-center text-center text-lg" >
2022-09-22 03:46:51 -07:00
< span className = "mr-1 font-mono text-th-fgd-1" > { ` ${ formatFixedDecimals (
2022-09-05 15:38:47 -07:00
amountIn . toNumber ( )
) } ` }</span>{' '}
2022-09-16 04:37:24 -07:00
{ inputTokenInfo ! . symbol }
< ArrowRightIcon className = "mx-2 h-5 w-5 text-th-fgd-4" / >
2022-09-22 03:46:51 -07:00
< span className = "mr-1 font-mono text-th-fgd-1" > { ` ${ formatFixedDecimals (
2022-09-05 15:38:47 -07:00
amountOut . toNumber ( )
) } ` }</span>{' '}
{ ` ${ outputTokenInfo . symbol } ` }
< / p >
2022-08-17 13:06:25 -07:00
< / div >
< / div >
2022-12-27 14:24:58 -08:00
< div className = "space-y-2 overflow-auto px-6" >
2022-08-25 13:24:37 -07:00
< div className = "flex justify-between" >
2022-12-29 02:59:56 -08:00
< p className = "text-sm text-th-fgd-3" > { t ( 'price' ) } < / p >
2022-08-25 13:24:37 -07:00
< div >
< div className = "flex items-center justify-end" >
2022-12-19 03:20:01 -08:00
< p className = "text-right font-mono text-sm text-th-fgd-2" >
2022-08-25 13:24:37 -07:00
{ swapRate ? (
< >
2022-09-16 04:37:24 -07:00
1 { ' ' }
2023-01-05 18:03:58 -08:00
< span className = "font-body tracking-wider" >
2022-09-16 04:37:24 -07:00
{ inputTokenInfo ! . name } ≈ { ' ' }
< / span >
2022-09-05 15:38:47 -07:00
{ formatFixedDecimals ( amountOut . div ( amountIn ) . toNumber ( ) ) } { ' ' }
2023-01-05 18:03:58 -08:00
< span className = "font-body tracking-wider" >
2022-09-16 04:37:24 -07:00
{ outputTokenInfo ? . symbol }
< / span >
2022-08-25 13:24:37 -07:00
< / >
) : (
< >
2022-09-16 04:37:24 -07:00
1 { ' ' }
2023-01-05 18:03:58 -08:00
< span className = "font-body tracking-wider" >
2022-09-16 04:37:24 -07:00
{ outputTokenInfo ? . symbol } ≈ { ' ' }
< / span >
2022-09-05 15:38:47 -07:00
{ formatFixedDecimals ( amountIn . div ( amountOut ) . toNumber ( ) ) } { ' ' }
2023-01-05 18:03:58 -08:00
< span className = "font-body tracking-wider" >
2022-09-16 04:37:24 -07:00
{ inputTokenInfo ! . symbol }
< / span >
2022-08-25 13:24:37 -07:00
< / >
) }
< / p >
2022-09-06 21:36:35 -07:00
< ArrowsRightLeftIcon
2022-12-19 03:20:01 -08:00
className = "default-transition ml-1 h-4 w-4 cursor-pointer text-th-fgd-2 hover:text-th-active"
2022-08-25 13:24:37 -07:00
onClick = { ( ) = > setSwapRate ( ! swapRate ) }
/ >
< / div >
2022-09-07 19:49:12 -07:00
< div className = "space-y-2 px-1 text-xs" >
2022-08-25 13:24:37 -07:00
{ coingeckoPrices ? . outputCoingeckoPrice &&
coingeckoPrices ? . inputCoingeckoPrice ? (
< div
2022-09-22 03:46:51 -07:00
className = { ` text-right font-mono ${
2022-12-16 14:12:07 -08:00
coinGeckoPriceDifference . gt ( 1 )
2022-11-30 19:32:32 -08:00
? 'text-th-down'
: 'text-th-up'
2022-08-25 13:24:37 -07:00
} ` }
>
2022-09-02 11:36:57 -07:00
{ Decimal . abs ( coinGeckoPriceDifference ) . toFixed ( 1 ) } % { ' ' }
2023-01-05 18:03:58 -08:00
< span className = "font-body text-th-fgd-3" > { ` ${
2022-09-02 11:36:57 -07:00
coinGeckoPriceDifference . lte ( 0 )
2022-08-25 13:24:37 -07:00
? 'cheaper'
: 'more expensive'
} than CoinGecko ` }</span>
< / div >
) : null }
< / div >
< / div >
< / div >
2022-08-17 13:06:25 -07:00
< div className = "flex justify-between" >
2022-12-29 02:59:56 -08:00
< p className = "text-sm text-th-fgd-3" >
{ t ( 'swap:minimum-received' ) }
< / p >
{ outputTokenInfo ? . decimals ? (
< p className = "text-right font-mono text-sm text-th-fgd-2" >
{ formatDecimal (
selectedRoute ? . otherAmountThreshold /
10 * * outputTokenInfo . decimals || 1 ,
outputTokenInfo . decimals
) } { ' ' }
2023-01-05 18:03:58 -08:00
< span className = "font-body tracking-wider" >
2022-12-29 02:59:56 -08:00
{ outputTokenInfo ? . symbol }
< / span >
< / p >
) : null }
< / div >
< div className = "flex justify-between" >
< p className = "text-sm text-th-fgd-3" > { t ( 'swap:price-impact' ) } < / p >
< p className = "text-right font-mono text-sm text-th-fgd-2" >
{ selectedRoute ? . priceImpactPct * 100 < 0.1
? '<0.1%'
: ` ${ ( selectedRoute ? . priceImpactPct * 100 ) . toFixed ( 2 ) } % ` }
< / p >
2022-08-17 13:06:25 -07:00
< / div >
2022-08-25 13:24:37 -07:00
{ borrowAmount ? (
2022-12-29 02:59:56 -08:00
< div className = "flex justify-between" >
< Tooltip
content = {
balance
? t ( 'swap:tooltip-borrow-balance' , {
balance : formatFixedDecimals ( balance ) ,
borrowAmount : formatFixedDecimals ( borrowAmount ) ,
token : inputTokenInfo?.symbol ,
rate : formatDecimal ( inputBank ! . getBorrowRateUi ( ) , 2 , {
fixed : true ,
} ) ,
} )
: t ( 'swap:tooltip-borrow-no-balance' , {
borrowAmount : formatFixedDecimals ( borrowAmount ) ,
token : inputTokenInfo?.symbol ,
rate : formatDecimal ( inputBank ! . getBorrowRateUi ( ) , 2 , {
fixed : true ,
} ) ,
} )
}
delay = { 250 }
>
< p className = "tooltip-underline text-sm text-th-fgd-3" >
{ t ( 'borrow-amount' ) }
2022-12-08 15:42:55 -08:00
< / p >
2022-12-29 02:59:56 -08:00
< / Tooltip >
< p className = "text-right font-mono text-sm text-th-fgd-2" >
~ { formatFixedDecimals ( borrowAmount ) } { ' ' }
2023-01-05 18:03:58 -08:00
< span className = "font-body tracking-wider" >
2022-12-29 02:59:56 -08:00
{ inputTokenInfo ? . symbol }
< / span >
< / p >
< / div >
2022-08-25 13:24:37 -07:00
) : null }
2022-12-29 02:59:56 -08:00
< div className = "flex items-center justify-between" >
< p className = "text-sm text-th-fgd-3" > { t ( 'swap:swap-route' ) } < / p >
< div
className = "flex items-center text-th-fgd-2 md:hover:cursor-pointer md:hover:text-th-fgd-3"
role = "button"
onClick = { ( ) = > setShowRoutesModal ( true ) }
>
< span className = "overflow-ellipsis whitespace-nowrap" >
{ selectedRoute ? . marketInfos . map ( ( info , index ) = > {
let includeSeparator = false
if (
selectedRoute ? . marketInfos . length > 1 &&
index !== selectedRoute ? . marketInfos . length - 1
) {
includeSeparator = true
}
return (
< span key = { index } > { ` ${ info ? . label } ${
includeSeparator ? 'x ' : ''
} ` }</span>
)
} ) }
< / span >
< PencilIcon className = "ml-2 h-4 w-4 hover:text-th-active" / >
< / div >
< / div >
2022-12-28 20:17:38 -08:00
< / div >
< / div >
< div className = "p-6" >
2022-12-29 02:59:56 -08:00
< div className = "mb-4 flex items-center justify-center" >
< Button
onClick = { onSwap }
className = "flex w-full items-center justify-center text-base"
size = "large"
>
{ submitting ? (
< Loading className = "mr-2 h-5 w-5" / >
) : (
< div className = "flex items-center" >
< ArrowsRightLeftIcon className = "mr-2 h-5 w-5" / >
{ t ( 'swap' ) }
< / div >
) }
< / Button >
< / div >
2022-12-28 20:17:38 -08:00
< div className = "rounded-md bg-th-bkg-2" >
< Disclosure >
{ ( { open } ) = > (
< >
< Disclosure.Button className = "default-transition flex w-full items-center justify-between rounded-md p-3" >
< p > { open ? t ( 'swap:hide-fees' ) : t ( 'swap:show-fees' ) } < / p >
< ChevronDownIcon
className = { ` ${
open ? 'rotate-180' : 'rotate-360'
} h - 5 w - 5 text - th - fgd - 3 ` }
/ >
< / Disclosure.Button >
< Disclosure.Panel className = "space-y-2 p-3 pt-0" >
{ borrowAmount ? (
< div className = "flex justify-between" >
2022-12-29 02:59:56 -08:00
< Tooltip
content = { t ( 'loan-origination-fee-tooltip' ) }
delay = { 250 }
>
2022-12-28 20:17:38 -08:00
< p className = "tooltip-underline text-sm text-th-fgd-3" >
{ t ( 'loan-origination-fee' ) }
< / p >
< / Tooltip >
< p className = "text-right font-mono text-sm text-th-fgd-2" >
~
{ formatFixedDecimals (
amountIn
. mul ( inputBank ! . loanOriginationFeeRate . toFixed ( ) )
. toNumber ( )
) } { ' ' }
2023-01-05 18:03:58 -08:00
< span className = "font-body tracking-wider" >
2022-12-28 20:17:38 -08:00
{ inputBank ! . name }
2022-12-29 02:59:56 -08:00
< / span > { ' ' }
(
{ formatFixedDecimals (
inputBank ! . loanOriginationFeeRate . toNumber ( ) * 100
) }
% )
2022-12-28 20:17:38 -08:00
< / p >
< / div >
) : null }
{ typeof feeValue === 'number' ? (
< div className = "flex justify-between" >
< p className = "text-sm text-th-fgd-3" > { t ( 'fee' ) } < / p >
< div className = "flex items-center" >
< p className = "text-right font-mono text-sm text-th-fgd-2" >
≈ $ { feeValue ? . toFixed ( 2 ) }
< / p >
< / div >
< / div >
) : (
selectedRoute ? . marketInfos . map ( ( info , index ) = > {
const feeToken = jupiterTokens . find (
( item ) = > item ? . address === info . lpFee ? . mint
)
return (
< div className = "flex justify-between" key = { index } >
< p className = "text-sm text-th-fgd-3" >
{ t ( 'swap:fees-paid-to' , {
route : info?.label ,
} ) }
< / p >
{ feeToken ? . decimals && (
< p className = "pl-4 text-right font-mono text-sm text-th-fgd-2" >
{ (
info . lpFee ? . amount /
Math . pow ( 10 , feeToken . decimals )
) . toFixed ( 6 ) } { ' ' }
2023-01-05 18:03:58 -08:00
< span className = "font-body tracking-wider" >
2022-12-28 20:17:38 -08:00
{ feeToken ? . symbol }
< / span > { ' ' }
(
{ ( info . lpFee ? . pct * 100 ) . toLocaleString (
undefined ,
{
maximumFractionDigits : 4 ,
}
) }
% )
< / p >
) }
< / div >
)
} )
2022-08-17 13:06:25 -07:00
) }
2022-12-28 20:17:38 -08:00
< / Disclosure.Panel >
< / >
) }
< / Disclosure >
< / div >
2022-08-17 13:06:25 -07:00
< / div >
2022-12-29 02:59:56 -08:00
{ showRoutesModal ? (
< RoutesModal
show = { showRoutesModal }
onClose = { ( ) = > setShowRoutesModal ( false ) }
setSelectedRoute = { setSelectedRoute }
selectedRoute = { selectedRoute }
routes = { routes }
inputTokenSymbol = { inputTokenInfo ! . name }
outputTokenInfo = { outputTokenInfo }
/ >
) : null }
2022-08-17 13:06:25 -07:00
< / div >
) : null
}
2022-12-07 13:33:35 -08:00
export default React . memo ( SwapReviewRouteInfo )