Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Routes error on request pay #413

Merged
merged 6 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 28 additions & 31 deletions src/components/Request/Pay/Views/Initial.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,9 @@ export const InitialView = ({
const { open } = useWeb3Modal()
const { setLoadingState, loadingState, isLoading } = useContext(context.loadingStateContext)
const {
selectedChainID,
selectedTokenData,
setSelectedChainID,
selectedTokenAddress,
setSelectedTokenAddress,
selectedTokenDecimals,
isTokenPriceFetchingComplete,
setIsXChain,
} = useContext(context.tokenSelectorContext)
const [errorState, setErrorState] = useState<{
Expand All @@ -48,26 +45,31 @@ export const InitialView = ({
const [linkState, setLinkState] = useState<RequestStatus>(RequestStatus.NOT_CONNECTED)
const [estimatedFromValue, setEstimatedFromValue] = useState<string>('0')
const createXChainUnsignedTx = async () => {
// This function is only makes sense if selectedTokenData is defined
// Chack that it is defined before calling this function
console.assert(selectedTokenData, 'selectedTokenData must be defined before estimating tx fee')
jjramirezn marked this conversation as resolved.
Show resolved Hide resolved

const xchainUnsignedTxs = await peanut.prepareXchainRequestFulfillmentTransaction({
fromToken: selectedTokenAddress,
fromChainId: selectedChainID,
fromToken: selectedTokenData!.tokenAddress,
fromChainId: selectedTokenData!.chainId,
senderAddress: address ?? '',
link: requestLinkData.link,
squidRouterUrl: 'https://apiplus.squidrouter.com/v2/route',
apiUrl: '/api/proxy/get',
provider: await peanut.getDefaultProvider(selectedChainID),
tokenType: selectedTokenAddress === ADDRESS_ZERO ? EPeanutLinkType.native : EPeanutLinkType.erc20,
fromTokenDecimals: selectedTokenDecimals as number,
provider: await peanut.getDefaultProvider(selectedTokenData!.chainId),
tokenType: selectedTokenData!.tokenAddress === ADDRESS_ZERO ? EPeanutLinkType.native : EPeanutLinkType.erc20,
fromTokenDecimals: selectedTokenData!.decimals as number,
})
return xchainUnsignedTxs
}

useEffect(() => {
const estimateTxFee = async () => {

setLinkState(RequestStatus.LOADING)
if (
selectedChainID === requestLinkData.chainId
&& utils.areTokenAddressesEqual(selectedTokenAddress, requestLinkData.tokenAddress)
selectedTokenData!.chainId === requestLinkData.chainId
&& utils.areTokenAddressesEqual(selectedTokenData!.tokenAddress, requestLinkData.tokenAddress)
jjramirezn marked this conversation as resolved.
Show resolved Hide resolved
) {
setErrorState({ showError: false, errorMessage: '' })
setIsFeeEstimationError(false)
Expand All @@ -80,6 +82,7 @@ export const InitialView = ({
const { feeEstimation, estimatedFromAmount } = txData
setEstimatedFromValue(estimatedFromAmount)
if (Number(feeEstimation) > 0) {
setErrorState({ showError: false, errorMessage: '' })
jjramirezn marked this conversation as resolved.
Show resolved Hide resolved
setIsFeeEstimationError(false)
setTxFee(Number(feeEstimation).toFixed(2))
setLinkState(RequestStatus.CLAIM)
Expand All @@ -97,26 +100,20 @@ export const InitialView = ({
}
}

const isXChain = selectedChainID !== requestLinkData.chainId
const isXChain = selectedTokenData?.chainId !== requestLinkData.chainId
|| !utils.areTokenAddressesEqual(
selectedTokenAddress,
selectedTokenData?.tokenAddress,
requestLinkData.tokenAddress
)
setIsXChain(isXChain)

// wait for token selector to fetch token price, both effects depend on
// selectedTokenAddress and selectedChainID, but we depend on that
// effect being completed first
if (!isConnected || (isXChain && !isTokenPriceFetchingComplete)) return
if (!isConnected || (isXChain && !selectedTokenData)) return

estimateTxFee()
}, [
selectedTokenAddress,
selectedChainID,
selectedTokenDecimals,
isTokenPriceFetchingComplete,
requestLinkData
])
}, [selectedTokenData, requestLinkData])
jjramirezn marked this conversation as resolved.
Show resolved Hide resolved

const handleConnectWallet = async () => {
open().finally(() => {
Expand Down Expand Up @@ -146,12 +143,12 @@ export const InitialView = ({
setErrorState({ showError: false, errorMessage: '' })
if (!unsignedTx) return
if (
selectedChainID === requestLinkData.chainId
&& utils.areTokenAddressesEqual(selectedTokenAddress, requestLinkData.tokenAddress)
selectedTokenData!.chainId === requestLinkData.chainId
&& utils.areTokenAddressesEqual(selectedTokenData!.tokenAddress, requestLinkData.tokenAddress)
jjramirezn marked this conversation as resolved.
Show resolved Hide resolved
){
await checkUserHasEnoughBalance({ tokenValue: requestLinkData.tokenAmount })
if (selectedChainID !== String(currentChain?.id)) {
await switchNetwork(selectedChainID)
if (selectedTokenData?.chainId !== String(currentChain?.id)) {
await switchNetwork(selectedTokenData!.chainId)
}
setLoadingState('Sign in wallet')
const hash = await sendTransactions({
Expand Down Expand Up @@ -184,8 +181,8 @@ export const InitialView = ({
onNext()
} else {
await checkUserHasEnoughBalance({ tokenValue: estimatedFromValue })
if (selectedChainID !== String(currentChain?.id)) {
await switchNetwork(selectedChainID)
if (selectedTokenData!.chainId !== String(currentChain?.id)) {
await switchNetwork(selectedTokenData!.chainId)
}
setLoadingState('Sign in wallet')
const xchainUnsignedTxs = await createXChainUnsignedTx()
Expand Down Expand Up @@ -329,12 +326,12 @@ export const InitialView = ({
<label className="font-bold">Network cost</label>
</div>
<label className="flex flex-row items-center justify-center gap-1 text-center text-sm font-normal leading-4">
{requestLinkData.chainId === selectedChainID &&
requestLinkData.tokenAddress === selectedTokenAddress
{requestLinkData.chainId === selectedTokenData?.chainId &&
requestLinkData.tokenAddress === selectedTokenData?.tokenAddress
? `$${utils.formatTokenAmount(estimatedGasCost, 3) ?? 0}`
: `$${txFee}`}
{requestLinkData.chainId === selectedChainID &&
requestLinkData.tokenAddress === selectedTokenAddress ? (
{requestLinkData.chainId === selectedTokenData?.chainId &&
requestLinkData.tokenAddress === selectedTokenData?.tokenAddress ? (
jjramirezn marked this conversation as resolved.
Show resolved Hide resolved
<MoreInfo
text={
estimatedGasCost && estimatedGasCost > 0
Expand Down
30 changes: 20 additions & 10 deletions src/context/tokenSelector.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,18 @@ export const tokenSelectorContext = createContext({
refetchXchainRoute: false as boolean,
setRefetchXchainRoute: (value: boolean) => {},
resetTokenContextProvider: () => {},
isTokenPriceFetchingComplete: false as boolean,
isXChain: false as boolean,
setIsXChain: (value: boolean) => {},
selectedTokenData: undefined as ITokenData | undefined,
})

type ITokenData = {
tokenAddress: string
chainId: string
decimals: number
price: number
}

/**
* Context provider to manage the selected token and chain ID set in the tokenSelector. Token price is fetched here and input denomination can be set here too.
* It handles fetching token prices, updating context values, and resetting the provider based on user preferences and wallet connection status.
Expand All @@ -37,8 +44,8 @@ export const TokenContextProvider = ({ children }: { children: React.ReactNode }
const [inputDenomination, setInputDenomination] = useState<inputDenominationType>('TOKEN')
const [refetchXchainRoute, setRefetchXchainRoute] = useState<boolean>(false)
const [selectedTokenDecimals, setSelectedTokenDecimals] = useState<number | undefined>(18)
const [isTokenPriceFetchingComplete, setTokenPriceFetchingComplete] = useState<boolean>(false)
const [isXChain, setIsXChain] = useState<boolean>(false)
const [selectedTokenData, setSelectedTokenData] = useState<ITokenData | undefined>(undefined)


const { isConnected } = useAccount()
Expand Down Expand Up @@ -66,6 +73,7 @@ export const TokenContextProvider = ({ children }: { children: React.ReactNode }
async function fetchAndSetTokenPrice(tokenAddress: string, chainId: string) {
jjramirezn marked this conversation as resolved.
Show resolved Hide resolved
try {
if (!consts.supportedMobulaChains.some((chain) => chain.chainId == chainId)) {
setSelectedTokenData(undefined)
setSelectedTokenPrice(undefined)
setSelectedTokenDecimals(undefined)
setInputDenomination('TOKEN')
Expand All @@ -78,13 +86,19 @@ export const TokenContextProvider = ({ children }: { children: React.ReactNode }
if (tokenPriceResponse?.price) {
setSelectedTokenPrice(tokenPriceResponse.price)
setSelectedTokenDecimals(tokenPriceResponse.decimals)
setTokenPriceFetchingComplete(true)
setSelectedTokenData({
tokenAddress,
chainId,
decimals: tokenPriceResponse.decimals,
price: tokenPriceResponse.price,
})
if (tokenPriceResponse.price === 1) {
setInputDenomination('TOKEN')
} else {
setInputDenomination('USD')
}
} else {
setSelectedTokenData(undefined)
setSelectedTokenPrice(undefined)
setSelectedTokenDecimals(undefined)
setInputDenomination('TOKEN')
Expand All @@ -95,22 +109,19 @@ export const TokenContextProvider = ({ children }: { children: React.ReactNode }
}
}


if (!isConnected) {
setSelectedTokenData(undefined)
setSelectedTokenPrice(undefined)
setSelectedTokenDecimals(undefined)
setInputDenomination('TOKEN')
return () => {
setTokenPriceFetchingComplete(false)
}
} else if (selectedTokenAddress && selectedChainID) {
setSelectedTokenData(undefined)
setSelectedTokenPrice(undefined)
setSelectedTokenDecimals(undefined)
setInputDenomination('TOKEN')
fetchAndSetTokenPrice(selectedTokenAddress, selectedChainID)
return () => {
jjramirezn marked this conversation as resolved.
Show resolved Hide resolved
isCurrent = false
setTokenPriceFetchingComplete(false)
}
}
}, [selectedTokenAddress, selectedChainID, isConnected])
Expand All @@ -121,7 +132,6 @@ export const TokenContextProvider = ({ children }: { children: React.ReactNode }
setSelectedTokenAddress(prefs.tokenAddress)
setSelectedChainID(prefs.chainId)
setSelectedTokenDecimals(prefs.decimals)
setTokenPriceFetchingComplete(true)
}
}, [])

Expand All @@ -141,9 +151,9 @@ export const TokenContextProvider = ({ children }: { children: React.ReactNode }
refetchXchainRoute,
setRefetchXchainRoute,
resetTokenContextProvider,
isTokenPriceFetchingComplete,
isXChain,
setIsXChain,
selectedTokenData,
}}
>
{children}
Expand Down