Skip to content

Commit

Permalink
feat: Add safe wallet support (#77)
Browse files Browse the repository at this point in the history
* Bump wagmi version

* Add RainbowKit, Merge Providers in one file

* Add sepolia for getTargetChainId

* Map over l2Networks in recover funds page

* Add Sepolia support in RecoverFunds

* Fix style

* Fix prettier

* Fix error logging

* Fix recover process

* Set popup for retryable

* Bump version

* Remove uppercase in walletConnect modal

* Fix autologin with walletConnect

* Add Sepolia to list of L1 network

* Add loading in RecoverFunds page

* Use network name rather than chainId

* Add checkbox

* Fix popup

* Add comments

* Fix alignment

* Add check for loading account type

* Fix alignment

* Add error for balance call

* Properly clear localStorage for walletConnect
  • Loading branch information
chrstph-dvx authored Mar 7, 2024
1 parent ab65183 commit a6b8d0e
Show file tree
Hide file tree
Showing 24 changed files with 1,965 additions and 630 deletions.
2 changes: 2 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ NEXT_PUBLIC_ARBITRUM_GOERLI_RPC_URL=
NEXT_PUBLIC_ARBITRUM_NOVA_RPC_URL=
NEXT_PUBLIC_ARBITRUM_SEPOLIA_RPC_URL=

NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=

NEXT_PUBLIC_LOCAL_ETHEREUM_RPC_URL=http://localhost:8545
NEXT_PUBLIC_LOCAL_ARBITRUM_RPC_URL=http://localhost:8547
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16.18.1
18
15 changes: 14 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
module.exports = {};
module.exports = {
// pino throw error during yarn build,
// see https://github.com/WalletConnect/walletconnect-monorepo/issues/1908#issuecomment-1487801131
webpack: (config, context) => {
if (config.plugins) {
config.plugins.push(
new context.webpack.IgnorePlugin({
resourceRegExp: /^(lokijs|pino-pretty|encoding)$/,
}),
);
}
return config;
},
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"dependencies": {
"@arbitrum/sdk": "^3.1.12",
"@ethersproject/bignumber": "^5.1.1",
"@rainbow-me/rainbowkit": "^0.12.18",
"@types/node": "^16.7.13",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
Expand All @@ -16,7 +17,7 @@
"react-feather": "^2.0.10",
"react-tooltip": "^5.5.1",
"typescript": "^4.4.2",
"wagmi": "^0.8.10"
"wagmi": "^0.12.19"
},
"engines": {
"node": ">=16"
Expand Down
12 changes: 9 additions & 3 deletions src/app/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ main {
max-width: 740px;
gap: 10px;
margin-bottom: var(--space-xl);
margin-left: auto;
margin-right: auto;
}

.form-inner {
Expand Down Expand Up @@ -119,7 +121,7 @@ main {
background-color: rgb(255, 255, 255);
}

button,
.button,
input[type='submit'] {
background-color: var(--blue);
color: #fff;
Expand All @@ -135,12 +137,12 @@ input[type='submit'] {
cursor: pointer;
}

button:hover,
.button:hover,
input[type='submit']:hover {
background-color: var(--blue-dark);
}

button:disabled {
.button:disabled {
background-color: var(--blue-lighter);
cursor: inherit;
}
Expand Down Expand Up @@ -274,3 +276,7 @@ ul {
.redeem-button-container {
text-align: center;
}

div[data-rk] {
width: 100%;
}
6 changes: 3 additions & 3 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NextPage } from 'next';
import { WagmiProvider } from '@/components/WagmiProvider';
import { Providers } from '@/components/Providers';
import { Logo } from '@/components/Logo';
import { Form } from '@/components/Form';

Expand All @@ -12,9 +12,9 @@ const PageIndex: NextPage = () => {
</header>

<main>
<WagmiProvider>
<Providers>
<Form />
</WagmiProvider>
</Providers>
</main>
</>
);
Expand Down
52 changes: 5 additions & 47 deletions src/app/recover-funds/[address]/RecoverFunds.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
'use client';
import { Address } from '@arbitrum/sdk';
import { BigNumber, utils, constants } from 'ethers';
import { useNetwork } from 'wagmi';
import { getProviderFromChainId, getTargetChainId } from '@/utils';
import { mapChainIdToName } from '@/utils/network';
import { BigNumber, utils } from 'ethers';
import '../style.css';

export interface OperationInfo {
balanceToRecover: BigNumber;
aliasedAddress: string;
chainId: string;
}

export const hasBalanceOverThreshold = (balanceToRecover: BigNumber) => {
Expand All @@ -16,59 +14,19 @@ export const hasBalanceOverThreshold = (balanceToRecover: BigNumber) => {
return balanceToRecover.gte(BigNumber.from(5_000_000_000_000_000));
};

export async function getData(
chainID: number,
address: string,
): Promise<OperationInfo | null> {
// First, obtain the aliased address of the signer
const destinationAddress = new Address(address);
const { value: aliasedAddress } = destinationAddress.applyAlias();

// And get its balance to find out the amount we are transferring
try {
const l2Provider = getProviderFromChainId(chainID);
const aliasedSignerBalance = await l2Provider.getBalance(aliasedAddress);

return {
balanceToRecover: hasBalanceOverThreshold(aliasedSignerBalance)
? aliasedSignerBalance
: constants.Zero,
aliasedAddress,
};
} catch (e) {
return {
balanceToRecover: constants.Zero,
aliasedAddress,
};
}
}

type Props = {
operationInfo: OperationInfo;
address: string;
};
const RecoverFunds = ({ operationInfo, address }: Props) => {
const { chain } = useNetwork();
const targetChainID = getTargetChainId(chain?.id);

// No funds to recover
if (!hasBalanceOverThreshold(operationInfo.balanceToRecover)) {
return (
<div className="funds-message">
There are no funds stuck on {operationInfo.aliasedAddress}
<br />
(Alias of {address}) on this network
{targetChainID ? ` (${targetChainID})` : ''}.
</div>
);
}
const l2ChainId = operationInfo.chainId;

return (
<div className="funds-message">
There are {utils.formatEther(operationInfo.balanceToRecover)} ETH on{' '}
{operationInfo.aliasedAddress}
<br />
(Alias of {address}).
(Alias of {address}) on this network {mapChainIdToName[l2ChainId] ?? ''}.
</div>
);
};
Expand Down
60 changes: 48 additions & 12 deletions src/app/recover-funds/[address]/RecoverFundsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,23 @@ import {
} from '@arbitrum/sdk';
import { Inbox__factory } from '@arbitrum/sdk/dist/lib/abi/factories/Inbox__factory';
import { getBaseFee } from '@arbitrum/sdk/dist/lib/utils/lib';
import { useNetwork, useSigner } from 'wagmi';
import { goerli, mainnet, sepolia, useNetwork, useSigner } from 'wagmi';
import { getProviderFromChainId, getTargetChainId } from '@/utils';
import { BigNumber } from 'ethers';
import { ChainId } from '@/utils/network';
import { useAccountType } from '@/utils/useAccountType';

function getL1ChainIdFromL2ChainId(l2ChainId: number | undefined) {
if (!l2ChainId) {
return ChainId.Mainnet;
}

return {
[ChainId.ArbitrumOne]: ChainId.Mainnet,
[ChainId.ArbitrumGoerli]: ChainId.Goerli,
[ChainId.ArbitrumSepolia]: ChainId.Sepolia,
}[l2ChainId];
}

function RecoverFundsButton({
balanceToRecover,
Expand All @@ -25,8 +39,12 @@ function RecoverFundsButton({
}) {
const [message, setMessage] = useState('');
const [loading, setLoading] = useState(false);
const { isSmartContractWallet, isLoading: isLoadingAccountType } =
useAccountType();
const { chain } = useNetwork();
const { data: signer } = useSigner({ chainId: chain?.id });
const { data: signer } = useSigner({
chainId: getL1ChainIdFromL2ChainId(chainID),
});

const handleRecover = useCallback(async () => {
if (!signer) {
Expand All @@ -45,10 +63,7 @@ function RecoverFundsButton({
setLoading(true);
setMessage('');

// We instantiate the Inbox factory object to make use of its methods
const targetChainID = getTargetChainId(chainID);

const baseL2Provider = getProviderFromChainId(targetChainID);
const baseL2Provider = getProviderFromChainId(chainID);
const l2Network = await getL2Network(baseL2Provider);
const inbox = Inbox__factory.connect(
l2Network.ethBridge.inbox,
Expand Down Expand Up @@ -143,26 +158,47 @@ function RecoverFundsButton({

if (!signer) return null;

if (chain?.id !== 1 && chain?.id !== 5) {
if (
chain?.id !== mainnet.id &&
chain?.id !== goerli.id &&
chain?.id !== sepolia.id
) {
return (
<div>Unknown L1 chain id. This chain is not supported by this tool</div>
);
}

if (chain?.id !== chainID) {
if (getTargetChainId(chain?.id) !== chainID) {
return (
<div>
To recover funds, connect to chain ${chain?.id} (${chain?.name})
To recover funds, connect to chain {chain?.id} ({chain?.name})
</div>
);
}

return (
<>
<div className="recover-funds-form">
<button id="recover-button" disabled={loading} onClick={handleRecover}>
Recover
</button>
<div>
<button
className="button"
id="recover-button"
disabled={loading}
onClick={handleRecover}
>
Recover
</button>
</div>
{loading && isSmartContractWallet && !isLoadingAccountType && (
<div className="flex flex-col">
<span>
<b>
To continue, please approve tx on your smart contract wallet.
</b>{' '}
If you have k of n signers, then k of n will need to sign.
</span>
</div>
)}
</div>
<div>
{message && (
Expand Down
Loading

0 comments on commit a6b8d0e

Please sign in to comment.