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

fix(extension): debounce on CIP-30 endpoint calls now starts after first event #1458

6 changes: 4 additions & 2 deletions apps/browser-extension-wallet/src/dapp-connector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { ExperimentsProvider } from '@providers/ExperimentsProvider/context';
import { AddressesDiscoveryOverlay } from 'components/AddressesDiscoveryOverlay';
import { useEffect, useState } from 'react';
import { getBackgroundStorage } from '@lib/scripts/background/storage';
import { NamiPopup } from './views/nami-mode';
import { NamiDappConnector } from './views/nami-mode/indexInternal';

const App = (): React.ReactElement => {
const [mode, setMode] = useState<'lace' | 'nami'>();
Expand All @@ -42,7 +42,9 @@ const App = (): React.ReactElement => {
<ThemeProvider>
<ExternalLinkOpenerProvider>
<AddressesDiscoveryOverlay>
<UIThemeProvider>{mode === 'nami' ? <NamiPopup /> : <DappConnectorView />}</UIThemeProvider>
<UIThemeProvider>
{mode === 'nami' ? <NamiDappConnector /> : <DappConnectorView />}
</UIThemeProvider>
</AddressesDiscoveryOverlay>
</ExternalLinkOpenerProvider>
</ThemeProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,29 +148,30 @@ export const DappCollateralContainer = (): React.ReactElement => {
}
}, [redirectToCreateFailure]);

if (!isCalculatingCollateral) {
if (insufficientBalance) {
return <InsufficientFunds />;
} else if (lockableUtxos.length > 0 && isInstanceOfCollateralInfoWithCollateralAmount(collateralInfo)) {
return (
<DappSetCollateral
dappInfo={dappInfo}
collateralInfo={collateralInfo}
reject={reject}
confirm={() => confirmCollateral(lockableUtxos)}
/>
);
}
// Allow user to create tx to set collateral
if (isCalculatingCollateral || !inMemoryWallet) {
return <MainLoader text={t('dapp.collateral.calculating')} />;
}

if (insufficientBalance) {
return <InsufficientFunds />;
} else if (lockableUtxos.length > 0 && isInstanceOfCollateralInfoWithCollateralAmount(collateralInfo)) {
return (
<CreateCollateral
<DappSetCollateral
dappInfo={dappInfo}
collateralInfo={collateralInfo}
confirm={(utxos: Wallet.Cardano.Utxo[]) => confirmCollateral(utxos)}
reject={reject}
confirm={() => confirmCollateral(lockableUtxos)}
/>
);
}

return <MainLoader text={t('dapp.collateral.calculating')} />;
// Allow user to create tx to set collateral
return (
<CreateCollateral
dappInfo={dappInfo}
collateralInfo={collateralInfo}
confirm={(utxos: Wallet.Cardano.Utxo[]) => confirmCollateral(utxos)}
reject={reject}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const ConfirmTransaction = (): React.ReactElement => {
setDappInfo,
signTxRequest: { request: req, set: setSignTxRequest }
} = useViewsFlowContext();
const { walletType, isHardwareWallet } = useWalletStore();
const { walletType, isHardwareWallet, walletInfo, inMemoryWallet } = useWalletStore();
const analytics = useAnalyticsContext();
const [confirmTransactionError] = useState(false);
const disallowSignTx = useDisallowSignTx(req);
Expand Down Expand Up @@ -83,7 +83,7 @@ export const ConfirmTransaction = (): React.ReactElement => {

return (
<Layout layoutClassname={cn(confirmTransactionError && styles.layoutError)} pageClassname={styles.spaceBetween}>
{req ? <DappTransactionContainer /> : <Skeleton loading />}
{req && walletInfo && inMemoryWallet ? <DappTransactionContainer /> : <Skeleton loading />}
{!confirmTransactionError && (
<div className={styles.actions}>
<Button
Expand Down
90 changes: 51 additions & 39 deletions apps/browser-extension-wallet/src/lib/scripts/background/cip30.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,48 +44,60 @@ export const confirmationCallback: walletCip30.CallbackConfirmation = {
// Also transactions can be submitted by the dApps externally
// once they've got the witnesss keys if they construct their own transactions
Promise.resolve(true),
signTx: pDebounce(async () => {
try {
const tab = await ensureUiIsOpenAndLoaded({ walletManager, walletRepository }, '#/dapp/sign-tx');
const ready = await userPromptService.readyToSignTx();
if (!ready) return false;
return cancelOnTabClose(tab);
} catch (error) {
console.error(error);
return Promise.reject(new ApiError(APIErrorCode.InternalError, 'Unable to sign transaction'));
}
}, DEBOUNCE_THROTTLE),
signData: pDebounce(async () => {
try {
const tab = await ensureUiIsOpenAndLoaded({ walletManager, walletRepository }, '#/dapp/sign-data');
const ready = await userPromptService.readyToSignData();
if (!ready) return false;
return cancelOnTabClose(tab);
} catch (error) {
console.error(error);
// eslint-disable-next-line unicorn/no-useless-undefined
return Promise.reject(new ApiError(APIErrorCode.InternalError, 'Unable to sign data'));
}
}, DEBOUNCE_THROTTLE),
getCollateral: pDebounce(async (args) => {
try {
const { namiMigration } = await getBackgroundStorage();
if (namiMigration.mode === 'nami') {
// User has to explicitly set collateral from the popup UI
return [];
signTx: pDebounce(
async () => {
try {
const tab = await ensureUiIsOpenAndLoaded({ walletManager, walletRepository }, '#/dapp/sign-tx');
const ready = await userPromptService.readyToSignTx();
if (!ready) return false;
return cancelOnTabClose(tab);
} catch (error) {
console.error(error);
return Promise.reject(new ApiError(APIErrorCode.InternalError, 'Unable to sign transaction'));
}
},
DEBOUNCE_THROTTLE,
{ before: true }
),
signData: pDebounce(
async () => {
try {
const tab = await ensureUiIsOpenAndLoaded({ walletManager, walletRepository }, '#/dapp/sign-data');
const ready = await userPromptService.readyToSignData();
if (!ready) return false;
return cancelOnTabClose(tab);
} catch (error) {
console.error(error);
// eslint-disable-next-line unicorn/no-useless-undefined
return Promise.reject(new ApiError(APIErrorCode.InternalError, 'Unable to sign data'));
}
},
DEBOUNCE_THROTTLE,
{ before: true }
),
getCollateral: pDebounce(
async (args) => {
try {
const { namiMigration } = await getBackgroundStorage();
if (namiMigration.mode === 'nami') {
// User has to explicitly set collateral from the popup UI
return [];
}

const dappInfo = await senderToDappInfo(args.sender);
dappSetCollateral$.next({ dappInfo, collateralRequest: args.data });
await ensureUiIsOpenAndLoaded({ walletManager, walletRepository }, '#/dapp/set-collateral');
const dappInfo = await senderToDappInfo(args.sender);
dappSetCollateral$.next({ dappInfo, collateralRequest: args.data });
await ensureUiIsOpenAndLoaded({ walletManager, walletRepository }, '#/dapp/set-collateral');

return userPromptService.getCollateralRequest();
} catch (error) {
// eslint-disable-next-line unicorn/no-useless-undefined
dappSetCollateral$.next(undefined);
throw new Error(error);
}
}, DEBOUNCE_THROTTLE)
return userPromptService.getCollateralRequest();
} catch (error) {
// eslint-disable-next-line unicorn/no-useless-undefined
dappSetCollateral$.next(undefined);
throw new Error(error);
}
},
DEBOUNCE_THROTTLE,
{ before: true }
)
};

const walletApi = walletCip30.createWalletApi(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ export const requestAccess: RequestAccess = async (sender: Runtime.MessageSender
return Promise.resolve(true);
};

export const requestAccessDebounced = pDebounce(requestAccess, DEBOUNCE_THROTTLE);
export const requestAccessDebounced = pDebounce(requestAccess, DEBOUNCE_THROTTLE, { before: true });
36 changes: 17 additions & 19 deletions apps/browser-extension-wallet/src/routes/DappConnectorView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { UnlockWalletContainer } from '@src/features/unlock-wallet';
import { useAppInit } from '@src/hooks';
import { dAppRoutePaths, walletRoutePaths } from '@routes';
import '@lib/i18n';
import 'antd/dist/antd.css';
import { Route, Switch } from 'react-router-dom';
import { MainLayout } from '@components/Layout';
import {
Expand Down Expand Up @@ -39,7 +38,7 @@ const isLastValidationExpired = (lastVerification: string, frequency: string): b
export const DappConnectorView = (): React.ReactElement => {
const { t } = useTranslation();
const [{ lastMnemonicVerification, mnemonicVerificationFrequency }] = useAppSettingsContext();
const { inMemoryWallet, cardanoWallet, walletInfo, initialHdDiscoveryCompleted } = useWalletStore();
const { cardanoWallet, hdDiscoveryStatus } = useWalletStore();
const { isWalletLocked, walletLock } = useWalletStore(lockWalletSelector);
const isSharedWallet = useWalletStore((state) => state.isSharedWallet);

Expand Down Expand Up @@ -108,21 +107,20 @@ export const DappConnectorView = (): React.ReactElement => {
return <UnlockWalletContainer />;
}

if (!!cardanoWallet && walletInfo && inMemoryWallet && initialHdDiscoveryCompleted) {
return (
<MainLayout useSimpleHeader hideFooter showAnnouncement={false}>
<Switch>
<Route exact path={dAppRoutePaths.dappConnect} component={DappConnect} />
<Route exact path={dAppRoutePaths.dappSignTx} component={SignTxFlowContainer} />
<Route exact path={dAppRoutePaths.dappSignData} component={SignDataFlowContainer} />
<Route exact path={dAppRoutePaths.dappTxSignSuccess} component={DappTransactionSuccess} />
<Route exact path={dAppRoutePaths.dappTxSignFailure} component={DappTransactionFail} />
<Route exact path={dAppRoutePaths.dappDataSignSuccess} component={DappSignDataSuccess} />
<Route exact path={dAppRoutePaths.dappDataSignFailure} component={DappSignDataFail} />
<Route exact path={dAppRoutePaths.dappSetCollateral} component={DappCollateralContainer} />
</Switch>
</MainLayout>
);
}
return <Loader className={styles.loader} />;
if (hdDiscoveryStatus !== 'Idle') return <Loader className={styles.loader} />;

return (
<MainLayout useSimpleHeader hideFooter showAnnouncement={false}>
<Switch>
<Route exact path={dAppRoutePaths.dappConnect} component={DappConnect} />
<Route exact path={dAppRoutePaths.dappSignTx} component={SignTxFlowContainer} />
<Route exact path={dAppRoutePaths.dappSignData} component={SignDataFlowContainer} />
<Route exact path={dAppRoutePaths.dappTxSignSuccess} component={DappTransactionSuccess} />
<Route exact path={dAppRoutePaths.dappTxSignFailure} component={DappTransactionFail} />
<Route exact path={dAppRoutePaths.dappDataSignSuccess} component={DappSignDataSuccess} />
<Route exact path={dAppRoutePaths.dappDataSignFailure} component={DappSignDataFail} />
<Route exact path={dAppRoutePaths.dappSetCollateral} component={DappCollateralContainer} />
</Switch>
</MainLayout>
);
};
Loading
Loading