Skip to content

Commit f110e6c

Browse files
committed
tracking safe type
1 parent 2a99224 commit f110e6c

8 files changed

Lines changed: 45 additions & 22 deletions

File tree

src/components/transactions/Bridge/BridgeDestinationInput.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ export const BridgeDestinationInput = ({
2323
onInputError: () => void;
2424
sourceChainId: number;
2525
}) => {
26-
const { data: isContractAddress, isFetching: fetchingIsContractAddress } = useIsContractAddress(
26+
const { data, isFetching: fetchingIsContractAddress } = useIsContractAddress(
2727
connectedAccount,
2828
sourceChainId
2929
);
30+
const isContractAddress = data?.isContract;
3031

3132
const [useConnectedAccount, setUseConnectedAccount] = useState(true);
3233
const [destinationAccount, setDestinationAccount] = useState('');

src/components/transactions/FlowCommons/RightHelperText.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ export const RightHelperText = ({ approvalHash, tryPermit }: RightHelperTextProp
3434
store.currentNetworkConfig,
3535
])
3636
);
37-
const { data: isContractAddress } = useIsContractAddress(account);
37+
const { data } = useIsContractAddress(account);
38+
const isContractAddress = data?.isContract;
3839
const usingPermit = tryPermit && walletApprovalMethodPreference;
3940
const isSigned = approvalHash === MOCK_SIGNED_HASH;
4041

src/components/transactions/GasStation/GasStation.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ export const GasStation: React.FC<GasStationProps> = ({
6363
const { data: poolReserves } = usePoolReservesHumanized(marketOnNetwork);
6464
const { data: gasPrice } = useGasPrice(selectedChainId);
6565
const { walletBalances } = useWalletBalances(marketOnNetwork);
66-
const { data: isContractAddress } = useIsContractAddress(account);
66+
const { data } = useIsContractAddress(account);
67+
const isContractAddress = data?.isContract;
6768
const nativeBalanceUSD = walletBalances[API_ETH_MOCK_ADDRESS.toLowerCase()]?.amountUSD;
6869
const { name, baseAssetSymbol } = getNetworkConfig(selectedChainId);
6970

src/helpers/provider.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,18 @@ function isEip7702EOA(code: string, account: string): boolean {
1515
return code.startsWith('0xef0100') || code.toLowerCase() === account.toLowerCase();
1616
}
1717

18-
const SAFE_BYTECODE =
19-
'0x608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033';
18+
const SAFE_BYTECODE_PREFIX = '0x608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e';
19+
20+
export const isCodeSafeWallet = (code: string) => {
21+
return code.startsWith(SAFE_BYTECODE_PREFIX);
22+
};
2023

2124
// Detect if a smart contract wallet is a Safe wallet
2225
export const isSafeWallet = async (user: string, provider: JsonRpcProvider): Promise<boolean> => {
2326
try {
2427
const code = await provider.getCode(user);
2528

26-
return code === SAFE_BYTECODE;
29+
return isCodeSafeWallet(code);
2730
} catch (error) {
2831
console.error('Error detecting Safe wallet:', error);
2932
return false;

src/hooks/useIsContractAddress.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useQuery } from '@tanstack/react-query';
2+
import { isCodeSafeWallet } from 'src/helpers/provider';
23
import { useRootStore } from 'src/store/root';
34
import { getProvider } from 'src/utils/marketsAndNetworksConfig';
45

@@ -11,6 +12,10 @@ export const useIsContractAddress = (address: string, chainId?: number) => {
1112
queryKey: ['isContractAddress', address],
1213
enabled: address !== '',
1314
staleTime: Infinity,
14-
select: (data) => data !== '0x',
15+
select: (data) => {
16+
const isContract = data !== '0x';
17+
const isSafeWallet = isCodeSafeWallet(data);
18+
return { isContract, isSafeWallet };
19+
},
1520
});
1621
};

src/libs/web3-data-provider/Web3Provider.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { BigNumber, PopulatedTransaction, utils } from 'ethers';
55
import React, { ReactElement, useEffect, useState } from 'react';
66
import { useIsContractAddress } from 'src/hooks/useIsContractAddress';
77
import { useRootStore } from 'src/store/root';
8+
import { WalletType } from 'src/store/walletSlice';
89
import { wagmiConfig } from 'src/ui-config/wagmiConfig';
910
import { hexToAscii } from 'src/utils/utils';
1011
import { UserRejectedRequestError } from 'viem';
@@ -49,8 +50,8 @@ export const Web3ContextProvider: React.FC<{ children: ReactElement }> = ({ chil
4950

5051
const [readOnlyModeAddress, setReadOnlyModeAddress] = useState<string | undefined>();
5152
const [switchNetworkError, setSwitchNetworkError] = useState<Error>();
52-
const [setAccount, setConnectedAccountIsContract] = useRootStore(
53-
useShallow((store) => [store.setAccount, store.setConnectedAccountIsContract])
53+
const [setAccount, setConnectedAccountType] = useRootStore(
54+
useShallow((store) => [store.setAccount, store.setConnectedAccountType])
5455
);
5556

5657
const account = address;
@@ -60,7 +61,9 @@ export const Web3ContextProvider: React.FC<{ children: ReactElement }> = ({ chil
6061
currentAccount = readOnlyModeAddress;
6162
}
6263

63-
const { data: isContractAddress } = useIsContractAddress(account || '', chainId);
64+
const { data } = useIsContractAddress(account || '', chainId);
65+
const isContractAddress = data?.isContract;
66+
const isSafeWallet = data?.isSafeWallet;
6467

6568
useEffect(() => {
6669
if (didInit) {
@@ -187,14 +190,16 @@ export const Web3ContextProvider: React.FC<{ children: ReactElement }> = ({ chil
187190

188191
useEffect(() => {
189192
if (!account) {
190-
setConnectedAccountIsContract(false);
193+
setConnectedAccountType(WalletType.EOA);
191194
return;
192195
}
193196

194197
if (isContractAddress) {
195-
setConnectedAccountIsContract(true);
198+
setConnectedAccountType(WalletType.CONTRACT);
199+
} else if (isSafeWallet) {
200+
setConnectedAccountType(WalletType.SAFE);
196201
}
197-
}, [isContractAddress, setConnectedAccountIsContract, account]);
202+
}, [isContractAddress, setConnectedAccountType, account]);
198203

199204
return (
200205
<Web3Context.Provider

src/store/poolSlice.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import { minBaseTokenRemainingByNetwork, optimizedPath } from 'src/utils/utils';
5555
import { StateCreator } from 'zustand';
5656

5757
import { RootStore } from './root';
58+
import { WalletType } from './walletSlice';
5859

5960
// TODO: what is the better name for this type?
6061
export type PoolReserve = {
@@ -703,9 +704,9 @@ export const createPoolSlice: StateCreator<
703704
get minRemainingBaseTokenBalance() {
704705
if (!get()) return '0.001';
705706

706-
const { currentNetworkConfig, currentChainId, connectedAccountIsContract } = { ...get() };
707+
const { currentNetworkConfig, currentChainId, connectedAccountType } = { ...get() };
707708

708-
if (connectedAccountIsContract) return '0';
709+
if (connectedAccountType !== WalletType.EOA) return '0';
709710

710711
const chainId = currentNetworkConfig.underlyingChainId || currentChainId;
711712
const min = minBaseTokenRemainingByNetwork[chainId];
@@ -771,7 +772,7 @@ export const createPoolSlice: StateCreator<
771772
return JSON.stringify(typeData);
772773
},
773774
estimateGasLimit: async (tx: PopulatedTransaction, chainId?: number) => {
774-
const { currentChainId, connectedAccountIsContract, jsonRpcProvider } = get();
775+
const { currentChainId, connectedAccountType, jsonRpcProvider } = get();
775776

776777
const effectiveChainId = chainId ?? currentChainId;
777778

@@ -781,7 +782,7 @@ export const createPoolSlice: StateCreator<
781782
*
782783
* See here for more details: https://github.com/zkSync-Community-Hub/zksync-developers/discussions/144
783784
*/
784-
if (effectiveChainId === ChainId.zksync && connectedAccountIsContract) {
785+
if (effectiveChainId === ChainId.zksync && connectedAccountType !== WalletType.EOA) {
785786
return tx;
786787
}
787788

src/store/walletSlice.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ export enum ApprovalMethod {
77
PERMIT = 'Signed message',
88
}
99

10+
export enum WalletType {
11+
EOA = 'EOA',
12+
CONTRACT = 'Contract',
13+
SAFE = 'Safe',
14+
}
15+
1016
export interface WalletSlice {
1117
account: string;
1218
walletType: string | undefined;
@@ -17,8 +23,8 @@ export interface WalletSlice {
1723
walletApprovalMethodPreference: ApprovalMethod;
1824
setWalletApprovalMethodPreference: (method: ApprovalMethod) => void;
1925
refreshWalletApprovalMethod: () => void;
20-
connectedAccountIsContract: boolean;
21-
setConnectedAccountIsContract: (isContract: boolean) => void;
26+
connectedAccountType: WalletType;
27+
setConnectedAccountType: (type: WalletType) => void;
2228
}
2329

2430
const getWalletPreferences = () => {
@@ -75,8 +81,8 @@ export const createWalletSlice: StateCreator<
7581
}));
7682
}
7783
},
78-
connectedAccountIsContract: false,
79-
setConnectedAccountIsContract(isContract) {
80-
set({ connectedAccountIsContract: isContract });
84+
connectedAccountType: WalletType.EOA,
85+
setConnectedAccountType(type) {
86+
set({ connectedAccountType: type });
8187
},
8288
});

0 commit comments

Comments
 (0)