Skip to content

Commit fcc8c5e

Browse files
authored
feat(ng): evm token/nft approvals (#408)
1 parent ffa3769 commit fcc8c5e

File tree

75 files changed

+2061
-232
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+2061
-232
lines changed

apps/legacy/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
"typecheck": "yarn tsc --skipLibCheck --noEmit"
1616
},
1717
"dependencies": {
18-
"@avalabs/avalanche-module": "1.9.10",
18+
"@avalabs/avalanche-module": "0.0.0-fix-nft-set-approval-for-all-20250829175304",
1919
"@avalabs/avalanchejs": "5.1.0-alpha.2",
20-
"@avalabs/bitcoin-module": "1.9.10",
20+
"@avalabs/bitcoin-module": "0.0.0-fix-nft-set-approval-for-all-20250829175304",
2121
"@avalabs/bridge-unified": "4.0.3",
2222
"@avalabs/core-bridge-sdk": "3.1.0-alpha.60",
2323
"@avalabs/core-chains-sdk": "3.1.0-alpha.60",
@@ -30,13 +30,13 @@
3030
"@avalabs/core-token-prices-sdk": "3.1.0-alpha.60",
3131
"@avalabs/core-utils-sdk": "3.1.0-alpha.60",
3232
"@avalabs/core-wallets-sdk": "3.1.0-alpha.60",
33-
"@avalabs/evm-module": "1.9.10",
33+
"@avalabs/evm-module": "0.0.0-fix-nft-set-approval-for-all-20250829175304",
3434
"@avalabs/glacier-sdk": "3.1.0-alpha.60",
35-
"@avalabs/hvm-module": "1.9.10",
35+
"@avalabs/hvm-module": "0.0.0-fix-nft-set-approval-for-all-20250829175304",
3636
"@avalabs/hw-app-avalanche": "0.14.1",
37-
"@avalabs/svm-module": "1.9.10",
37+
"@avalabs/svm-module": "0.0.0-fix-nft-set-approval-for-all-20250829175304",
3838
"@avalabs/types": "3.1.0-alpha.60",
39-
"@avalabs/vm-module-types": "1.9.10",
39+
"@avalabs/vm-module-types": "0.0.0-fix-nft-set-approval-for-all-20250829175304",
4040
"@blockaid/client": "0.10.0",
4141
"@coinbase/cbpay-js": "1.6.0",
4242
"@core/common": "workspace:*",

apps/legacy/src/localization/locales/en/translation.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,7 @@
10461046
"Transaction has been cancelled": "Transaction has been cancelled",
10471047
"Transaction has been rejected": "Transaction has been rejected",
10481048
"Transaction has failed": "Transaction has failed",
1049-
"Transaction pre-exution is unavailable. The displayed token list might be incomplete.": "Transaction pre-exution is unavailable. The displayed token list might be incomplete.",
1049+
"Transaction pre-execution is unavailable. The displayed token list might be incomplete.": "Transaction pre-execution is unavailable. The displayed token list might be incomplete.",
10501050
"Transaction rejected": "Transaction rejected",
10511051
"Transaction timed out": "Transaction timed out",
10521052
"Transfer": "Transfer",

apps/legacy/src/pages/SignTransaction/components/TxBalanceChange.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const TxBalanceChange = ({
4242
tooltip={
4343
showNoPreExecWarning
4444
? t(
45-
'Transaction pre-exution is unavailable. The displayed token list might be incomplete.',
45+
'Transaction pre-execution is unavailable. The displayed token list might be incomplete.',
4646
)
4747
: ''
4848
}

apps/next/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"@avalabs/core-wallets-sdk": "3.1.0-alpha.60",
2323
"@avalabs/k2-alpine": "1.228.0",
2424
"@avalabs/types": "3.1.0-alpha.60",
25-
"@avalabs/vm-module-types": "1.9.10",
25+
"@avalabs/vm-module-types": "0.0.0-fix-nft-set-approval-for-all-20250829175304",
2626
"@core/common": "workspace:*",
2727
"@core/messaging": "workspace:*",
2828
"@core/service-worker": "workspace:*",

apps/next/src/config/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { TransactionPriority } from '@core/types';
2+
13
export const CORE_WEB_BASE_URL =
24
process.env.CORE_WEB_BASE_URL ?? 'https://core.app';
35
export const BUG_BOUNTIES_URL =
@@ -9,3 +11,6 @@ export const CORE_FEEDBACK_URL =
911
'https://docs.google.com/forms/d/e/1FAIpQLSdUQiVnJoqQ1g_6XTREpkSB5vxKKK8ba5DRjhzQf1XVeET8Rw/viewform?usp=pp_url&entry.2070152111=Core%20browser%20extension&entry.903657115=${extensionVersion}&entry.1148340936=${os}';
1012

1113
export const DARK_THEME_SURFACE_COLOR = '#404046';
14+
15+
export const DEFAULT_FEE_PRESET: TransactionPriority = 'low';
16+
export const DEFAULT_FEE_PRESET_C_CHAIN: TransactionPriority = 'high';

apps/next/src/localization/locales/en/translation.json

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"All keys contained in this file are already imported.": "All keys contained in this file are already imported.",
3939
"Allow Chrome to access your camera to scan the QR code.": "Allow Chrome to access your camera to scan the QR code.",
4040
"Alternatively, open any authenticator app and enter this code:": "Alternatively, open any authenticator app and enter this code:",
41+
"Amount": "Amount",
4142
"Amount is too low": "Amount is too low",
4243
"Amount is too small to proceed.": "Amount is too small to proceed.",
4344
"An error occurred while computing the price.": "An error occurred while computing the price.",
@@ -47,6 +48,7 @@
4748
"Anyone with this private key can access the account(s) associated with it": "Anyone with this private key can access the account(s) associated with it",
4849
"Approval transaction failed": "Approval transaction failed",
4950
"Approve": "Approve",
51+
"Approves all {{token}}": "Approves all {{token}}",
5052
"Approving will give this dApp access to your active account.": "Approving will give this dApp access to your active account.",
5153
"Are you sure that you want to cancel this request?": "Are you sure that you want to cancel this request?",
5254
"Are you sure you want to delete selected accounts?": "Are you sure you want to delete selected accounts?",
@@ -62,6 +64,7 @@
6264
"Average password - this will do": "Average password - this will do",
6365
"Awesome!": "Awesome!",
6466
"Back": "Back",
67+
"Balance change unavailable.": "Balance change unavailable.",
6568
"Balances loading...": "Balances loading...",
6669
"Bitcoin": "Bitcoin",
6770
"Bridge initialization failed": "Bridge initialization failed",
@@ -75,6 +78,7 @@
7578
"Cancel": "Cancel",
7679
"Cancel Export": "Cancel Export",
7780
"Cancel request": "Cancel request",
81+
"Cancel transaction": "Cancel transaction",
7882
"Cancellation Failed": "Cancellation Failed",
7983
"Cancelling will require you to restart the 2 day waiting period": "Cancelling will require you to restart the 2 day waiting period",
8084
"Cancelling...": "Cancelling...",
@@ -91,7 +95,6 @@
9195
"Closing the settings menu will require you to restart the 2 day waiting period.": "Closing the settings menu will require you to restart the 2 day waiting period.",
9296
"Code copied to clipboard": "Code copied to clipboard",
9397
"Code verification error": "Code verification error",
94-
"Coming soon!": "Coming soon!",
9598
"Confirm": "Confirm",
9699
"Confirm Bridge": "Confirm Bridge",
97100
"Confirm addresses": "Confirm addresses",
@@ -133,6 +136,7 @@
133136
"Dark": "Dark",
134137
"Decide what default view works best for you, either a floating interface or a sidebar docked to the side to show more content": "Decide what default view works best for you, either a floating interface or a sidebar docked to the side to show more content",
135138
"Decrypt Recovery Phrase": "Decrypt Recovery Phrase",
139+
"Default": "Default",
136140
"Delete": "Delete",
137141
"Delete selected": "Delete selected",
138142
"Deleting these accounts is permanent and cannot be undone": "Deleting these accounts is permanent and cannot be undone",
@@ -148,6 +152,7 @@
148152
"Download Ledger Live to update": "Download Ledger Live to update",
149153
"Drop your file here to upload": "Drop your file here to upload",
150154
"Edit network fee": "Edit network fee",
155+
"Edit spend limit": "Edit spend limit",
151156
"Email address": "Email address",
152157
"Enable a sandbox environment for testing without using real funds": "Enable a sandbox environment for testing without using real funds",
153158
"English": "English",
@@ -196,6 +201,7 @@
196201
"French": "French",
197202
"Gas fees paid by Core": "Gas fees paid by Core",
198203
"Gas limit": "Gas limit",
204+
"Gasless funding failed": "Gasless funding failed",
199205
"General": "General",
200206
"Generate a new account in your active wallet": "Generate a new account in your active wallet",
201207
"German": "German",
@@ -297,6 +303,7 @@
297303
"Name this contact": "Name this contact",
298304
"Name your Passkey": "Name your Passkey",
299305
"Name your Yubikey": "Name your Yubikey",
306+
"Network": "Network",
300307
"Network error": "Network error",
301308
"Network fee amount": "Network fee amount",
302309
"New password": "New password",
@@ -364,11 +371,14 @@
364371
"Private Key Import Failed": "Private Key Import Failed",
365372
"Private Key Imported": "Private Key Imported",
366373
"Private key copied!": "Private key copied!",
374+
"Proceed anyway": "Proceed anyway",
375+
"Proceed with caution.": "Proceed with caution.",
367376
"Protect your data and ensure the highest level of security for your Core wallet.": "Protect your data and ensure the highest level of security for your Core wallet.",
368377
"Public key not found": "Public key not found",
369378
"Receive crypto": "Receive crypto",
370379
"Recent": "Recent",
371380
"Recents": "Recents",
381+
"Recipient": "Recipient",
372382
"Recovery Phrase": "Recovery Phrase",
373383
"Recovery Phrase {{number}}": "Recovery Phrase {{number}}",
374384
"Recovery methods": "Recovery methods",
@@ -423,6 +433,7 @@
423433
"Send to": "Send to",
424434
"Sending this token is not supported yet.": "Sending this token is not supported yet.",
425435
"Sending this type of token is not supported by Core": "Sending this type of token is not supported by Core",
436+
"Set a limit that you will allow to automatically spend.": "Set a limit that you will allow to automatically spend.",
426437
"Settings": "Settings",
427438
"Show me Trending Tokens": "Show me Trending Tokens",
428439
"Show password": "Show password",
@@ -440,6 +451,7 @@
440451
"Something went wrong. Please try again.": "Something went wrong. Please try again.",
441452
"Sort": "Sort",
442453
"Spanish": "Spanish",
454+
"Spend limit": "Spend limit",
443455
"Staked": "Staked",
444456
"Stay updated on latest airdrops, events and more! You can unsubscribe anytime. For more details, see our <policyLink>Privacy Policy</policyLink>": "Stay updated on latest airdrops, events and more! You can unsubscribe anytime. For more details, see our <policyLink>Privacy Policy</policyLink>",
445457
"Storage update failed": "Storage update failed",
@@ -456,6 +468,7 @@
456468
"The amount cannot be lower than the bridging fee": "The amount cannot be lower than the bridging fee",
457469
"The base fee is set by the network and changes frequently. Any difference between the set max base fee and the actual base fee will be refunded.": "The base fee is set by the network and changes frequently. Any difference between the set max base fee and the actual base fee will be refunded.",
458470
"The bridging fee is unknown": "The bridging fee is unknown",
471+
"The displayed token list might be incomplete.": "The displayed token list might be incomplete.",
459472
"The export process could not be completed. Please try again.": "The export process could not be completed. Please try again.",
460473
"The field is required": "The field is required",
461474
"The key you entered is invalid. Please try again": "The key you entered is invalid. Please try again",
@@ -474,13 +487,15 @@
474487
"This asset cannot be bridged": "This asset cannot be bridged",
475488
"This email looks invalid": "This email looks invalid",
476489
"This file requires a password. This password was set when the file was created.": "This file requires a password. This password was set when the file was created.",
490+
"This is a placeholder screen just to allow us to reject/approve some wallet-specific interactions (i.e. chain switching).": "This is a placeholder screen just to allow us to reject/approve some wallet-specific interactions (i.e. chain switching).",
477491
"This is taking longer than expected. Please try again later.": "This is taking longer than expected. Please try again later.",
478492
"This key gives access to your account’s addresses": "This key gives access to your account’s addresses",
479493
"This operation requires {{total}} approvals.": "This operation requires {{total}} approvals.",
480494
"This phrase is your access key to your wallet.": "This phrase is your access key to your wallet.",
481495
"This phrase is your access key to your wallet. Carefully write it down and store it in a safe location": "This phrase is your access key to your wallet. Carefully write it down and store it in a safe location",
482496
"This recovery phrase is already imported.": "This recovery phrase is already imported.",
483497
"This token contract is missing a required method.": "This token contract is missing a required method.",
498+
"This transaction has been flagged as malicious. <span>I understand the risk and want to proceed anyway.</span>": "This transaction has been flagged as malicious. <span>I understand the risk and want to proceed anyway.</span>",
484499
"This transaction would likely fail": "This transaction would likely fail",
485500
"This wallet is already imported": "This wallet is already imported",
486501
"This wallet is already imported.": "This wallet is already imported.",
@@ -497,6 +512,7 @@
497512
"Transaction has been cancelled": "Transaction has been cancelled",
498513
"Transaction has been rejected": "Transaction has been rejected",
499514
"Transaction has failed": "Transaction has failed",
515+
"Transaction pre-execution is unavailable.": "Transaction pre-execution is unavailable.",
500516
"Transaction rejected": "Transaction rejected",
501517
"Transaction successful": "Transaction successful",
502518
"Transaction timed out": "Transaction timed out",
@@ -530,6 +546,8 @@
530546
"Unknown network": "Unknown network",
531547
"Unknown network fee": "Unknown network fee",
532548
"Unknown transaction error": "Unknown transaction error",
549+
"Unlimited": "Unlimited",
550+
"Unlimited {{currency}}": "Unlimited {{currency}}",
533551
"Unlock airdrops": "Unlock airdrops",
534552
"Unnamed FIDO Device": "Unnamed FIDO Device",
535553
"Unsupporetd secret type": "Unsupporetd secret type",
@@ -568,6 +586,7 @@
568586
"Wallet renamed": "Wallet renamed",
569587
"Wallet secrets not found for the requested ID": "Wallet secrets not found for the requested ID",
570588
"We were not able to verify this code. Please try again.": "We were not able to verify this code. Please try again.",
589+
"We're unable to cover the gas fees for your transaction at this time. As a result, this feature has been disabled.": "We're unable to cover the gas fees for your transaction at this time. As a result, this feature has been disabled.",
571590
"Weak password! Try adding more characters": "Weak password! Try adding more characters",
572591
"When you connect to a dApp, it will appear here": "When you connect to a dApp, it will appear here",
573592
"Wrong quote provider": "Wrong quote provider",
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { useCallback } from 'react';
2+
import { Typography } from '@avalabs/k2-alpine';
3+
import { useTranslation } from 'react-i18next';
4+
5+
import { ActionStatus } from '@core/types';
6+
import { useApproveAction, useGetRequestId } from '@core/ui';
7+
8+
import {
9+
ActionDrawer,
10+
ApprovalScreenTitle,
11+
LoadingScreen,
12+
Styled,
13+
} from './components';
14+
15+
export const ExtensionActionApprovalScreen = () => {
16+
const { t } = useTranslation();
17+
18+
const requestId = useGetRequestId();
19+
const { action, updateAction, cancelHandler } = useApproveAction(requestId);
20+
21+
const approve = useCallback(async () => {
22+
updateAction({
23+
status: ActionStatus.SUBMITTING,
24+
id: requestId,
25+
});
26+
}, [updateAction, requestId]);
27+
28+
if (!action) {
29+
return <LoadingScreen />;
30+
}
31+
32+
return (
33+
<Styled.ApprovalScreenPage>
34+
<Styled.NoScrollStack>
35+
<ApprovalScreenTitle
36+
title={t('🚧 Placeholder - needs implementation 🚧')}
37+
/>
38+
<Typography variant="body3">
39+
{t(
40+
'This is a placeholder screen just to allow us to reject/approve some wallet-specific interactions (i.e. chain switching).',
41+
)}
42+
</Typography>
43+
</Styled.NoScrollStack>
44+
<ActionDrawer
45+
open
46+
approve={approve}
47+
reject={cancelHandler}
48+
action={action}
49+
/>
50+
</Styled.ApprovalScreenPage>
51+
);
52+
};

apps/next/src/pages/Approve/GenericApprovalScreen.tsx

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,41 @@ import {
1717
LoadingScreen,
1818
Styled,
1919
UnsupportedNetworkScreen,
20+
MaliciousTxOverlay,
21+
NoteWarning,
2022
} from './components';
23+
import { hasNoteWarning, hasOverlayWarning } from './lib';
24+
import { useGasless } from './hooks';
2125

2226
const POLLED_BALANCES = [TokenType.NATIVE, TokenType.ERC20]; // Approval screen should always have the latest balance
2327

2428
export const GenericApprovalScreen = () => {
2529
useLiveBalance(POLLED_BALANCES);
26-
2730
const requestId = useGetRequestId();
2831
const { getNetwork, networks } = useNetworkContext();
32+
2933
const { action, updateAction, cancelHandler, error } =
3034
useApproveAction<DisplayData>(requestId);
3135

32-
// TODO: handle gasless
36+
const { tryFunding, setGaslessDefaultValues } = useGasless({ action });
37+
3338
const approve = useCallback(async () => {
34-
updateAction(
35-
{
36-
status: ActionStatus.SUBMITTING,
37-
id: requestId,
38-
},
39-
false, // TODO: handle hardware wallets
40-
);
41-
}, [updateAction, requestId]);
39+
tryFunding(() => {
40+
updateAction(
41+
{
42+
status: ActionStatus.SUBMITTING,
43+
id: requestId,
44+
},
45+
false, // TODO: handle hardware wallets
46+
);
47+
});
48+
}, [updateAction, requestId, tryFunding]);
49+
50+
const cancel = useCallback(() => {
51+
// Reset the gasless state
52+
setGaslessDefaultValues();
53+
cancelHandler();
54+
}, [cancelHandler, setGaslessDefaultValues]);
4255

4356
const network = action ? getNetwork(action.scope) : undefined;
4457

@@ -55,7 +68,7 @@ export const GenericApprovalScreen = () => {
5568
// TODO: Should we still allow approvals?
5669
return (
5770
<UnsupportedNetworkScreen>
58-
<ActionDrawer open reject={cancelHandler} action={action} />
71+
<ActionDrawer open reject={cancel} action={action} />
5972
</UnsupportedNetworkScreen>
6073
);
6174
}
@@ -64,6 +77,9 @@ export const GenericApprovalScreen = () => {
6477
<Styled.ApprovalScreenPage>
6578
<Styled.NoScrollStack>
6679
<ApprovalScreenTitle title={action.displayData.title} />
80+
{hasNoteWarning(action) && (
81+
<NoteWarning alert={action.displayData.alert} />
82+
)}
6783
<Stack flexGrow={1} px={2}>
6884
<ActionDetails
6985
network={network}
@@ -72,13 +88,15 @@ export const GenericApprovalScreen = () => {
7288
error={error}
7389
/>
7490
</Stack>
75-
<ActionDrawer
76-
open
77-
approve={approve}
78-
reject={cancelHandler}
79-
action={action}
80-
/>
91+
<ActionDrawer open approve={approve} reject={cancel} action={action} />
8192
</Styled.NoScrollStack>
93+
{hasOverlayWarning(action) && (
94+
<MaliciousTxOverlay
95+
open={hasOverlayWarning(action)}
96+
cancelHandler={cancelHandler}
97+
alert={action.displayData.alert}
98+
/>
99+
)}
82100
</Styled.ApprovalScreenPage>
83101
);
84102
};

apps/next/src/pages/Approve/components/ActionDetails/ActionDetails.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { isEvmNetwork } from '@core/types';
1+
import { isBtcNetwork, isEvmNetwork } from '@core/types';
22

33
import { ActionDetailsProps } from '../../types';
44

55
import { EvmActionDetails } from './evm/EvmActionDetails';
66
import { UnknownActionDetails } from './UnknownActionDetails';
7+
import { BtcActionDetails } from './btc';
78

89
export const ActionDetails = ({
910
network,
@@ -22,6 +23,17 @@ export const ActionDetails = ({
2223
);
2324
}
2425

26+
if (isBtcNetwork(network)) {
27+
return (
28+
<BtcActionDetails
29+
network={network}
30+
action={action}
31+
updateAction={updateAction}
32+
error={error}
33+
/>
34+
);
35+
}
36+
2537
return (
2638
<UnknownActionDetails
2739
network={network}

0 commit comments

Comments
 (0)