Skip to content

Commit

Permalink
Merge pull request #33 from multiversx/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
ioandanpopa authored Oct 18, 2024
2 parents 9a9dc5f + 8532387 commit f8b98b1
Show file tree
Hide file tree
Showing 13 changed files with 1,661 additions and 1,693 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [[2.0.0](https://github.com/multiversx/mx-sdk-dapp-swap/pull/33)] - 2024-10-18

- [Fixes balances not updating on authenticated change. Many other fixes.](https://github.com/multiversx/mx-sdk-dapp-swap/pull/32)

## [[1.8.4](https://github.com/multiversx/mx-sdk-dapp-swap/pull/30)] - 2024-10-09

- [Update isError flag on useQueryWrapper](https://github.com/multiversx/mx-sdk-dapp-swap/pull/29)
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-dapp-swap",
"version": "1.8.4",
"version": "2.0.0",
"description": "A library to hold the main logic for swapping between tokens on the MultiversX blockchain",
"author": "MultiversX",
"license": "GPL-3.0-or-later",
Expand Down Expand Up @@ -98,7 +98,7 @@
"react-tooltip": "4.2.21"
},
"dependencies": {
"@apollo/client": "3.7.16",
"@apollo/client": "3.11.8",
"@multiversx/sdk-network-providers": "2.2.1",
"anchorme": "2.1.2",
"bech32": "2.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,29 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import { ApolloClient, from, HttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { onError } from '@apollo/client/link/error';
import { useClosureRef } from '@multiversx/sdk-dapp/hooks/useClosureRef';
import { print } from 'graphql';
import {
AuthorizationHeadersRequestParamsType,
SwapGraphQLAddressEnum
SwapGraphQLAddressEnum,
AuthorizationHeadersRequestParamsType
} from 'types';
import { AuthorizationContext } from './context';

export const SwapAuthorizationProvider = ({
getAccessToken,
getAuthorizationHeaders,
children,
accessToken,
graphQLAddress,
children
isAccessTokenLoading = false,
getAuthorizationHeaders
}: {
accessToken?: string;
children: React.ReactNode;
isAccessTokenLoading?: boolean;
graphQLAddress: SwapGraphQLAddressEnum | string;
getAccessToken?: () => Promise<string>;
getAuthorizationHeaders?: (
requestParams: AuthorizationHeadersRequestParamsType
) => Promise<void | null | Record<string, string>>;
children: React.ReactNode;
}) => {
const [accessToken, setAccessToken] = useState<string>();

const onGetAccessToken = async () => {
let newAccessToken = '';

try {
newAccessToken = (await getAccessToken?.()) ?? '';
} catch (e) {
console.error(e);
}
setAccessToken(newAccessToken);
return newAccessToken;
};

const onGetAccessTokenRef = useClosureRef(onGetAccessToken);
useEffect(() => {
//initialize token for isAuthenticated boolean
onGetAccessTokenRef?.current?.();
}, []);

const authMiddleware = setContext(async (req, { headers }) => {
const requestParams: AuthorizationHeadersRequestParamsType = {
url: graphQLAddress,
Expand All @@ -57,11 +38,11 @@ export const SwapAuthorizationProvider = ({

const authorizationHeaders = await getAuthorizationHeaders?.(requestParams);

const token = await onGetAccessTokenRef.current();

const authorizationBearerHeader = {
Authorization: `Bearer ${token}`
};
const authorizationBearerHeader = accessToken
? {
Authorization: `Bearer ${accessToken}`
}
: {};

return {
headers: {
Expand Down Expand Up @@ -107,10 +88,10 @@ export const SwapAuthorizationProvider = ({
return (
<AuthorizationContext.Provider
value={{
isAuthenticated: accessToken != null && accessToken != '',
isAccessTokenLoading: accessToken == null,
client,
accessToken,
client
isAccessTokenLoading,
isAuthenticated: Boolean(accessToken)
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { createContext, useContext } from 'react';
import { ApolloClient, NormalizedCacheObject } from '@apollo/client';

export type AuthorizationContextType = {
isAuthenticated?: boolean;
accessToken?: string;
isAuthenticated?: boolean;
isAccessTokenLoading: boolean;
client?: ApolloClient<NormalizedCacheObject>;
};

export const AuthorizationContext = createContext<AuthorizationContextType>({
isAuthenticated: false,
accessToken: '',
isAuthenticated: false,
isAccessTokenLoading: true
});

Expand Down
33 changes: 16 additions & 17 deletions src/components/TokenSelect/TokenSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,24 @@ export const TokenSelect = ({
const ref = React.useRef(null);
const disableOption = (option: any) => option.value === disabledOption?.value;

const FormatOptionLabel = () => (
option: any,
{ context }: { context: any }
) => {
const { label, value: val, token } = option;
const inDropdown = context === 'menu';
const isDisabled = disableOption(option);
const FormatOptionLabel =
() =>
(option: any, { context }: { context: any }) => {
const { label, value: val, token } = option;
const inDropdown = context === 'menu';
const isDisabled = disableOption(option);

const args = {
inDropdown,
label,
value: val,
token,
isDisabled,
handleDisabledOptionClick
};
const args = {
inDropdown,
label,
value: val,
token,
isDisabled,
handleDisabledOptionClick
};

return <SelectOption {...args} />;
};
return <SelectOption {...args} />;
};

return (
<div className='dapp-core-swap-select-container'>
Expand Down
17 changes: 10 additions & 7 deletions src/hooks/useQueryWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { useIsPageVisible } from 'hooks';
export const useQueryWrapper = <TData>({
query,
queryOptions,
refetchTrigger,
isPollingEnabled = false,
isRefetchEnabled = false,
refetchTrigger
isRefetchEnabled = false
}: {
query: DocumentNode;
refetchTrigger?: number;
isPollingEnabled?: boolean;
isRefetchEnabled?: boolean;
queryOptions?: QueryHookOptions<TData>;
refetchTrigger?: number;
}) => {
const isPageVisible = useIsPageVisible();

Expand All @@ -30,15 +30,18 @@ export const useQueryWrapper = <TData>({
} = useQuery<TData>(query, {
notifyOnNetworkStatusChange: true,
fetchPolicy: 'no-cache', // used for first run
nextFetchPolicy: 'no-cache', // "cache-and-network", // used for subsequent runs
nextFetchPolicy: 'no-cache', // used for subsequent runs
...queryOptions
});

// listening on queryOptions resets the polling interval -> posibile race condition fix
const startPollingCallback = useCallback(() => {
if (isPageVisible && isPollingEnabled && !error) {
startPolling(POLLING_INTERVAL);
} else {
stopPolling();
}
}, [isPageVisible, isPollingEnabled, startPolling, error]);
}, [isPageVisible, isPollingEnabled, error, queryOptions]);

// mount and unmount
useEffect(() => {
Expand All @@ -58,14 +61,14 @@ export const useQueryWrapper = <TData>({

refetch();
startPollingCallback();
}, [refetchTrigger, isRefetchEnabled, refetch, startPollingCallback]);
}, [refetchTrigger, isRefetchEnabled]);

const isLoading = data == null && loading;
const isError = Boolean(error);
const isRefetching = loading;

return {
data,
data: isError ? undefined : data,
error,
isError,
isLoading,
Expand Down
1 change: 1 addition & 0 deletions src/hooks/useSwapFormHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const useSwapFormHandlers = ({

const handleOnChangeSwapRoute = (swapRoute?: SwapRouteType) => {
if (!swapRoute) {
setActiveRoute(undefined);
return;
}

Expand Down
46 changes: 23 additions & 23 deletions src/hooks/useSwapRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import { useQueryWrapper } from './useQueryWrapper';

export interface GetSwapRouteType {
amountIn?: string;
amountOut?: string;
tokenInID: string;
amountOut?: string;
tokenOutID: string;
wrappingAmount?: string; // used only by wrapping queries
tolerancePercentage?: number;
wrappingAmount?: string; // used only by wrapping queries
}

export interface GetSwapRouteVariablesType
Expand All @@ -34,19 +34,19 @@ export interface GetSwapRouteVariablesType
}

export interface UseSwapRouteType {
isSwapRouteError?: boolean;
swapRouteError?: string;
isAmountInLoading: boolean;
getSwapRoute: (props: GetSwapRouteType) => void;
swapRoute?: SwapRouteType;
isSwapRouteError?: boolean;
isAmountInLoading: boolean;
isSwapRouteLoading: boolean;
isAmountOutLoading: boolean;
transactions?: RawTransactionType[];
swapActionType?: SwapActionTypesEnum;
previousFetchVariables: React.MutableRefObject<
GetSwapRouteVariablesType | undefined
>;
getSwapRoute: (props: GetSwapRouteType) => void;
refetch: (variables?: Partial<OperationVariables>) => void;
transactions?: RawTransactionType[];
isSwapRouteLoading: boolean;
isAmountOutLoading: boolean;
swapActionType?: SwapActionTypesEnum;
}

export const useSwapRoute = ({
Expand Down Expand Up @@ -107,21 +107,20 @@ export const useSwapRoute = ({
isPollingEnabled
});

const handleOnCompleted = (
data?: SwapRouteQueryResponseType | WrappingQueryResponseType
) => {
if (!variables || !data) {
const handleOnCompleted = () => {
if (!variables) {
setSwapRoute(undefined);
setSwapRouteError(undefined);
setSwapRouteError(translateSwapError(error?.message));
return;
}

switch (swapActionType) {
case SwapActionTypesEnum.wrap:
case SwapActionTypesEnum.unwrap:
const { wrapEgld, unwrapEgld } = data as WrappingQueryResponseType;
const wrapTx = (data as WrappingQueryResponseType)?.wrapEgld;
const unwrapTx = (data as WrappingQueryResponseType)?.unwrapEgld;
const tx = wrapTx ?? unwrapTx;

const transaction = wrapEgld ?? unwrapEgld;
const swapType = variables.amountIn ? FIXED_INPUT : FIXED_OUTPUT;
const amount = variables.amountIn ?? variables.amountOut;

Expand All @@ -145,19 +144,20 @@ export const useSwapRoute = ({

intermediaryAmounts: [],
pairs: [],
transactions: transaction ? [transaction] : []
transactions: tx ? [tx] : []
};

setSwapRoute(wrappingSwapRoute);
// ignore errors for wrapping because the endpoints don't work when not authenticated
setSwapRouteError(undefined);
setSwapRoute(wrappingSwapRoute);
break;
default:
const { swap } = data as SwapRouteQueryResponseType;

setSwapRoute(swap);

const swap = (data as SwapRouteQueryResponseType)?.swap;
const translatedError = translateSwapError(error?.message);

// we do not set partial routes
setSwapRouteError(translatedError);
setSwapRoute(translatedError ? undefined : swap);
}
};

Expand Down Expand Up @@ -186,7 +186,7 @@ export const useSwapRoute = ({
previousFetchVariablesRef.current = variables;
};

useEffect(() => handleOnCompleted(data), [data]);
useEffect(handleOnCompleted, [data, error]);

const isAmountOutLoading = Boolean(
(isLoading || isRefetching) && previousFetchVariablesRef.current?.amountIn
Expand Down
7 changes: 1 addition & 6 deletions src/hooks/useTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ interface UseTokensType {
}

export const useTokens = (options?: UseTokensType) => {
const { client, isAuthenticated, isAccessTokenLoading } =
useAuthorizationContext();
const { client, isAuthenticated } = useAuthorizationContext();

if (!client) {
throw new Error('Swap GraphQL client not initialized');
Expand Down Expand Up @@ -110,10 +109,6 @@ export const useTokens = (options?: UseTokensType) => {
});

const getTokens = (options?: GetTokensType) => {
if (isAccessTokenLoading) {
return;
}

const variables = {
limit: options?.limit ?? DEFAULT_LIMIT,
offset: options?.offset ?? DEFAULT_OFFSET,
Expand Down
Loading

0 comments on commit f8b98b1

Please sign in to comment.