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

(Feature) - #114 show tx status #117

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

.idea

# dependencies
/node_modules
/.pnp
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@apollo/client": "^3.3.11",
"@swingby-protocol/ip-check": "^2.1.0",
"@swingby-protocol/pulsar": "^3.15.3",
"@swingby-protocol/sdk": "v1.2.0-alpha.3",
"@swingby-protocol/sdk": "v1.2.0-alpha.5",
"big.js": "6.0.3",
"bnc-onboard": "^1.38.3",
"graphql": "^15.5.0",
Expand Down
68 changes: 37 additions & 31 deletions src/components/VerticalWidgetView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Props = {
top?: React.ReactNode;
children?: React.ReactNode;
swap?: SwapData | null;
fromBTC: boolean;
} & Testable;

export const VerticalWidgetView = ({
Expand All @@ -30,6 +31,7 @@ export const VerticalWidgetView = ({
children,
swap,
'data-testid': testId,
fromBTC,
}: Props) => {
const {
query: { disableNavigation },
Expand All @@ -39,44 +41,48 @@ export const VerticalWidgetView = ({
return (
<Container data-testid={buildTestId('')}>
<StepViewContainer>
{layout !== 'widget-small' && (top || onClickBack) && (
<>
<PulsarThemeProvider theme="accent">
<FancyTopContainer data-testid={buildTestId('top')}>
<PulsarThemeProvider theme="accent">
<FancyTopContainer data-testid={buildTestId('top')}>
{layout !== 'widget-small' && (top || onClickBack) && (
<>
<PulsarThemeProvider theme="accent">
<FancyTopContainer data-testid={buildTestId('top')}>
<Space size="widgetVerticalPadding" />
<NavBarContainer>
{typeof disableNavigation === 'undefined' && onClickBack && (
<BackButton onClick={onClickBack} data-testid={buildTestId('back-btn')} />
)}
<Space size="box" shape="fill" />
{swap?.currencyDeposit !== 'BTC' && <ConnectWallet />}
</NavBarContainer>
<TopContent>{top}</TopContent>
<Space size="city" />
</FancyTopContainer>
</PulsarThemeProvider>
</>
)}
{layout === 'widget-small' && (top || onClickBack) && (
<LightTopContainer data-testid={buildTestId('top')}>
<Space size="widgetVerticalPadding" />
<NavBarContainer>
{typeof disableNavigation === 'undefined' && onClickBack && (
{onClickBack && (
<BackButton onClick={onClickBack} data-testid={buildTestId('back-btn')} />
)}
<Space size="box" shape="fill" />
{swap?.currencyDeposit !== 'BTC' && <ConnectWallet />}
{fromBTC ? null : <ConnectWallet />}
</NavBarContainer>
<TopContent>{top}</TopContent>
<Space size="city" />
</FancyTopContainer>
</PulsarThemeProvider>
</>
)}
{layout === 'widget-small' && (top || onClickBack) && (
<LightTopContainer data-testid={buildTestId('top')}>
{top && <TopContent>{top}</TopContent>}
</LightTopContainer>
)}
<Space size="widgetVerticalPadding" />
<NavBarContainer>
{onClickBack && (
<BackButton onClick={onClickBack} data-testid={buildTestId('back-btn')} />
)}
<Space size="box" shape="fill" />
<ConnectWallet />
</NavBarContainer>
{top && <TopContent>{top}</TopContent>}
</LightTopContainer>
)}
<Space size="widgetVerticalPadding" />
{children && (
<BottomContainer data-testid={buildTestId('bottom')} hasNoTop={!top}>
{children}
</BottomContainer>
)}
<Space size="widgetVerticalPadding" />
{children && (
<BottomContainer data-testid={buildTestId('bottom')} hasNoTop={!top}>
{children}
</BottomContainer>
)}
<Space size="widgetVerticalPadding" />
</FancyTopContainer>
</PulsarThemeProvider>
</StepViewContainer>
</Container>
);
Expand Down
2 changes: 2 additions & 0 deletions src/modules/i18n/files/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
"widget.status-label-short.COMPLETED": "Sent",
"widget.status-label-short.REFUNDED": "Refunded",
"widget.status-label-short.EXPIRED": "This swap has expired",
"widget.status-label-long.TITLE": "To send the funds, you can connect your wallet or scan the QR code",
"widget.status-label-long.TITLE-BELLOW": "Or scan the QR code",
"widget.status-label-long.WAITING": "Send exactly {value} to",
"widget.status-label-long.WAITING.note": " ",
"widget.status-label-long.WAITING_CONFIRMATIONS": "Waiting for confirmations…",
Expand Down
2 changes: 1 addition & 1 deletion src/modules/store/index.tsx
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { useStore } from './store';
export { initialStore } from './store';
10 changes: 4 additions & 6 deletions src/modules/store/store.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useMemo } from 'react';
import { DefaultRootState } from 'react-redux';
import { createStore, applyMiddleware, Store } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';

import { isServer } from '../env';

import { rootReducer } from './root';

let store: Store | undefined;
Expand All @@ -26,14 +27,11 @@ const initializeStore = (preloadedState: Partial<DefaultRootState> | undefined =
}

// For SSG and SSR always create a new store
if (typeof window === 'undefined') return _store;
if (isServer) return _store;
// Create the store once in the client
if (!store) store = _store;

return _store;
};

export function useStore(initialState: Partial<DefaultRootState> | undefined = undefined) {
const store = useMemo(() => initializeStore(initialState), [initialState]);
return store;
}
export const initialStore = initializeStore();
7 changes: 6 additions & 1 deletion src/modules/web3/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ export const OnboardProvider = ({ children }: { children?: React.ReactNode }) =>
return;
}

if (onboard) {
logger.debug('"onboard" already defined, will skip');
return;
}

const walletSubscription = (wallet: Wallet) => {
if (wallet.name) {
saveLastUsedProvider(wallet.name);
Expand All @@ -70,7 +75,7 @@ export const OnboardProvider = ({ children }: { children?: React.ReactNode }) =>
subscriptions: { address: setAddress, wallet: walletSubscription },
}),
);
}, [context, currentBridge]);
}, [context, currentBridge, onboard]);

useEffect(() => {
onboard?.config({ darkMode: theme.pulsar.id !== 'PulsarLight' });
Expand Down
18 changes: 9 additions & 9 deletions src/modules/web3/useTransferToken.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CONTRACTS } from '@swingby-protocol/sdk';
import { Big } from 'big.js';
import type { DefaultRootState } from 'react-redux';
import Web3 from 'web3';
import { TransactionConfig } from 'web3-eth';
import { TransactionConfig, TransactionReceipt } from 'web3-eth';
import { createToast } from '@swingby-protocol/pulsar';

import { logger } from '../logger';
Expand All @@ -18,6 +18,7 @@ export const useTransferToken = () => {
const context = useSdkContext();
const { onboard, wallet, address } = useOnboard();
const [loading, setLoading] = useState(false);
const [txHash, setTxHash] = useState<string | null>(null);
const [error, setError] = useState<Error | null>(null);

const transfer = useCallback(
Expand Down Expand Up @@ -84,17 +85,16 @@ export const useTransferToken = () => {
);
}

return watchTransaction({
return await watchTransaction({
coin: swap.currencyDeposit,
tx: web3.eth.sendTransaction({ ...rawTx, gas: estimatedGas }),
})
.on('error', (error) => {
onReceipt: (receipt: TransactionReceipt) => setLoading(false),
onError: (error: Error) => {
setLoading(false);
setError(error);
})
.on('receipt', () => {
setLoading(false);
});
},
onTxHash: (transactionHash: string) => setTxHash(transactionHash),
});
} catch (err: any) {
setLoading(false);
setError(err);
Expand All @@ -110,5 +110,5 @@ export const useTransferToken = () => {
[address, context, onboard, wallet],
);

return useMemo(() => ({ loading, error, transfer }), [loading, error, transfer]);
return useMemo(() => ({ loading, error, transfer, txHash }), [loading, error, transfer, txHash]);
};
19 changes: 15 additions & 4 deletions src/modules/web3/watchTransaction/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@ import { logger } from '../../logger';

import { TransferToast } from './TransferToast';

type WatchTransactionProps = {
coin: SkybridgeCoin;
tx: PromiEvent<TransactionReceipt>;
onReceipt: (receipt: TransactionReceipt) => void;
onTxHash: (txHash: string) => void;
onError: (error: Error) => void;
};

export const watchTransaction = ({
coin,
tx,
}: {
coin: SkybridgeCoin;
tx: PromiEvent<TransactionReceipt>;
}) => {
onError,
onReceipt,
onTxHash,
}: WatchTransactionProps) => {
let transactionHash: string | null = null;

tx.on('transactionHash', (hash) => {
Expand All @@ -24,6 +32,7 @@ export const watchTransaction = ({
type: 'default',
toastId: 'transaction-result',
});
onTxHash(transactionHash);
})
.on('confirmation', (confirmations) => {
updateToast({
Expand All @@ -45,6 +54,7 @@ export const watchTransaction = ({
type: 'danger',
toastId: 'transaction-result',
});
onError(error);
})
.on('receipt', (receipt) => {
createOrUpdateToast({
Expand All @@ -58,6 +68,7 @@ export const watchTransaction = ({
type: receipt.status ? 'success' : 'danger',
toastId: 'transaction-result',
});
onReceipt(receipt);
});

return tx;
Expand Down
12 changes: 5 additions & 7 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ import { Favicon } from '../components/Favicon';
import { graphQlEndpoint } from '../modules/env';
import { languages } from '../modules/i18n';
import { WidgetLayoutProvider } from '../modules/layout';
import { useStore } from '../modules/store';
import { initialStore } from '../modules/store';
import { SdkContextGateKeeper } from '../modules/store/sdkContext';
import { GlobalStyles } from '../modules/styles';
import { OnboardGlobalStyles, OnboardProvider } from '../modules/web3';

function MyApp({ Component, pageProps, router }: AppProps) {
const store = useStore();

const App = ({ Component, pageProps, router }: AppProps) => {
const apolloClient = new ApolloClient({
uri: graphQlEndpoint,
cache: new InMemoryCache(),
Expand Down Expand Up @@ -54,7 +52,7 @@ function MyApp({ Component, pageProps, router }: AppProps) {
<PulsarGlobalStyles />
<GlobalStyles />
<OnboardGlobalStyles />
<ReduxProvider store={store}>
<ReduxProvider store={initialStore}>
<SdkContextGateKeeper mode={router.query.mode}>
<OnboardProvider>
<WidgetLayoutProvider>
Expand All @@ -78,6 +76,6 @@ function MyApp({ Component, pageProps, router }: AppProps) {
</PulsarThemeProvider>
</ApolloProvider>
);
}
};

export default MyApp;
export default App;
36 changes: 21 additions & 15 deletions src/scenes/SwapDetails/Vertical/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
ProgressContainer,
RowLink,
StyledQRCode,
StyledQRContainer,
TransferButtonsContainer,
} from './styled';
import { Top } from './Top';
Expand All @@ -35,7 +36,7 @@ export const Vertical = ({ resource, swap }: VerticalProps) => {
const { locale } = useIntl();
const context = useSdkContext();
const { address } = useOnboard();
const { transfer, loading: isTransferring } = useTransferToken();
const { transfer, loading: isTransferring, txHash } = useTransferToken();
const [hasTransactionSucceeded, setTransactionSucceeded] = useState(false);
const { assertTermsSignature } = useAssertTermsSignature();

Expand All @@ -49,13 +50,15 @@ export const Vertical = ({ resource, swap }: VerticalProps) => {
}, [context, swap]);

const inboundLink = useMemo(() => {
if (!swap || !swap.txDepositId) return undefined;
if (!swap) return undefined;
if (!txHash && !swap.txDepositId) return undefined;

return buildExplorerLink({
context,
coin: swap.currencyDeposit,
transactionId: swap.txDepositId,
transactionId: swap.txDepositId ? swap.txDepositId : (txHash as string),
});
}, [context, swap]);
}, [context, swap, txHash]);

const doTransfer = useCallback(async () => {
try {
Expand Down Expand Up @@ -95,10 +98,8 @@ export const Vertical = ({ resource, swap }: VerticalProps) => {
top={<Top swap={swap} data-testid={buildTestId('')} />}
data-testid={buildTestId('')}
swap={swap}
fromBTC={swap.currencyDeposit === 'BTC'}
>
{address && swap.status === 'WAITING' && (isTransferring || hasTransactionSucceeded) && (
<Loading />
)}
{address &&
supportsWeb3 &&
swap.status === 'WAITING' &&
Expand All @@ -114,15 +115,19 @@ export const Vertical = ({ resource, swap }: VerticalProps) => {
swap.status === 'WAITING' &&
!isTransferring &&
!hasTransactionSucceeded && (
<StyledQRCode
value={getTransferUriFor({
address: swap.addressDeposit,
coin: swap.currencyDeposit,
amount: swap.amountDeposit,
})}
/>
<StyledQRContainer>
<FormattedMessage id="widget.status-label-long.TITLE-BELLOW" />
<StyledQRCode
value={getTransferUriFor({
address: swap.addressDeposit,
coin: swap.currencyDeposit,
amount: swap.amountDeposit,
})}
/>
</StyledQRContainer>
)}
{swap.status !== 'WAITING' && (

{txHash && (
<ProgressContainer>
<SwapProgress
messages={SwapProgress.defaultMessages({ locale })}
Expand All @@ -133,6 +138,7 @@ export const Vertical = ({ resource, swap }: VerticalProps) => {
/>
</ProgressContainer>
)}

<>
<Space size="town" shape="fill" />
<ExplorerContainer>
Expand Down
Loading