-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rename TempDeployer* to Deployer*
- Loading branch information
Showing
14 changed files
with
391 additions
and
182 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
NEXT_PUBLIC_WALLET_CONNECT_ID=12345678901234567890123456789012 | ||
NEXT_PUBLIC_CHAIN_WALLET_WHITELISTS='{"eclipsemainnet":["Salmon", "Backpack", "Connect by Drift"]}' | ||
NEXT_PUBLIC_TEMP_WALLET_ENCRYPTION_KEY=todoReplaceMeWithAnyStrongPassword! # Any strong password will work | ||
NEXT_PUBLIC_TEMP_WALLET_ENCRYPTION_SALT=3424521f5cc25e6d05bd062eedc3c33d9201118dbb4baa3f7656c8dd34a95e28 # E.g. Sha256 of 'hyperlane-deploy-app' | ||
NEXT_PUBLIC_DEPLOYER_WALLET_ENCRYPTION_KEY=todoReplaceMeWithAnyStrongPassword! # Any strong password will work | ||
NEXT_PUBLIC_DEPLOYER_WALLET_ENCRYPTION_SALT=3424521f5cc25e6d05bd062eedc3c33d9201118dbb4baa3f7656c8dd34a95e28 # E.g. Sha256 of 'hyperlane-deploy-app' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import Link from 'next/link'; | ||
|
||
import { objLength } from '@hyperlane-xyz/utils'; | ||
import { DocsIcon, HistoryIcon, IconButton, useModal } from '@hyperlane-xyz/widgets'; | ||
import { links } from '../../consts/links'; | ||
import { DeployerRecoveryModal } from '../../features/deployerWallet/DeployerRecoveryModal'; | ||
import { useStore } from '../../features/store'; | ||
import { Color } from '../../styles/Color'; | ||
import { GasIcon } from '../icons/GasIcon'; | ||
|
||
export function FloatingButtonRow() { | ||
const { setIsSideBarOpen, isSideBarOpen, deployerKeys } = useStore((s) => ({ | ||
setIsSideBarOpen: s.setIsSideBarOpen, | ||
isSideBarOpen: s.isSideBarOpen, | ||
deployerKeys: s.deployerKeys, | ||
})); | ||
|
||
const { isOpen, open, close } = useModal(); | ||
|
||
const hasTempKeys = objLength(deployerKeys) > 0; | ||
|
||
return ( | ||
<div className="absolute -top-8 right-2 flex items-center gap-3"> | ||
{hasTempKeys && ( | ||
<IconButton | ||
className={`p-0.5 ${styles.roundedCircle} `} | ||
title="Deployer Accounts" | ||
onClick={open} | ||
> | ||
<GasIcon color={Color.primary['500']} height={20} width={20} className="p-0.5" /> | ||
</IconButton> | ||
)} | ||
<IconButton | ||
className={`p-0.5 ${styles.roundedCircle} `} | ||
title="History" | ||
onClick={() => setIsSideBarOpen(!isSideBarOpen)} | ||
> | ||
<HistoryIcon color={Color.primary['500']} height={22} width={22} /> | ||
</IconButton> | ||
<Link | ||
href={links.warpDocs} | ||
target="_blank" | ||
className={`p-0.5 ${styles.roundedCircle} ${styles.link}`} | ||
title="Documentation" | ||
> | ||
<DocsIcon color={Color.primary['500']} height={21} width={21} className="p-px" /> | ||
</Link> | ||
<DeployerRecoveryModal isOpen={isOpen} close={close} /> | ||
</div> | ||
); | ||
} | ||
|
||
const styles = { | ||
link: 'hover:opacity-70 active:opacity-60', | ||
roundedCircle: 'rounded-full bg-white', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export const MIN_CHAIN_BALANCE = 1; // 1 Wei | ||
export const WARP_DEPLOY_GAS_UNITS = BigInt(1e7); | ||
export const REFUND_FEE_PADDING_FACTOR = 1.1; | ||
export const MIN_DEPLOYER_BALANCE_TO_SHOW = BigInt(1e15); // 0.001 ETH |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { Button, CopyButton, Modal, SpinnerIcon, tryClipboardSet } from '@hyperlane-xyz/widgets'; | ||
import { PropsWithChildren, useEffect, useMemo } from 'react'; | ||
import { toast } from 'react-toastify'; | ||
import { H2 } from '../../components/text/Headers'; | ||
import { MIN_DEPLOYER_BALANCE_TO_SHOW } from '../../consts/consts'; | ||
import { Color } from '../../styles/Color'; | ||
import { useMultiProvider } from '../chains/hooks'; | ||
import { getChainDisplayName } from '../chains/utils'; | ||
import { useDeployerBalances } from './balances'; | ||
import { useRefundDeployerAccounts } from './refund'; | ||
import { DeployerWallets, TypedWallet } from './types'; | ||
import { getDeployerWalletKey, useDeployerWallets, useRemoveDeployerWallet } from './wallets'; | ||
|
||
export function DeployerRecoveryModal({ isOpen, close }: { isOpen: boolean; close: () => void }) { | ||
const { wallets } = useDeployerWallets(); | ||
|
||
// Close modal when no wallets are found | ||
useEffect(() => { | ||
if (isOpen && !Object.values(wallets).length) close(); | ||
}, [isOpen, wallets, close]); | ||
|
||
return ( | ||
<Modal isOpen={isOpen} close={close} panelClassname="p-4 flex flex-col items-center gap-4"> | ||
<H2>Temporary Deployer Accounts</H2> | ||
<p className="text-center text-sm text-gray-700"> | ||
Once the balances are successfully refunded, these temporary accounts can be safely deleted. | ||
</p> | ||
<AccountList wallets={wallets} /> | ||
<div className="py-2"> | ||
<Balances isOpen={isOpen} wallets={wallets} /> | ||
</div> | ||
</Modal> | ||
); | ||
} | ||
|
||
function AccountList({ wallets }: { wallets: DeployerWallets }) { | ||
const removeDeployerKey = useRemoveDeployerWallet(); | ||
|
||
const walletList = useMemo(() => Object.values(wallets), [wallets]); | ||
|
||
const onClickCopyPrivateKey = (wallet: TypedWallet) => { | ||
try { | ||
const pk = getDeployerWalletKey(wallet); | ||
tryClipboardSet(pk); | ||
toast.success('Private key copied to clipboard'); | ||
} catch { | ||
toast.error('Unable to retrieve private key'); | ||
} | ||
}; | ||
|
||
const onClickDeleteAccount = (wallet: TypedWallet) => { | ||
removeDeployerKey(wallet.protocol); | ||
}; | ||
|
||
return ( | ||
<> | ||
{walletList.map((w) => ( | ||
<div key={w.type} className="space-y-2 rounded-lg bg-primary-500/5 p-2"> | ||
<div className="flex items-center gap-2"> | ||
<span className="text-xs">{w.address}</span> | ||
<CopyButton copyValue={w.address} width={12} height={12} className="opacity-50" /> | ||
</div> | ||
<div className="flex items-center justify-center gap-10 text-sm text-accent-500"> | ||
<Button onClick={() => onClickCopyPrivateKey(w)}>Copy Private Key</Button> | ||
<Button onClick={() => onClickDeleteAccount(w)}>Delete Account</Button> | ||
</div> | ||
</div> | ||
))} | ||
</> | ||
); | ||
} | ||
|
||
function Balances({ isOpen, wallets }: { isOpen: boolean; wallets: DeployerWallets }) { | ||
const multiProvider = useMultiProvider(); | ||
const { balances, isFetching, refetch } = useDeployerBalances(wallets); | ||
const { refund, isPending } = useRefundDeployerAccounts(refetch); | ||
|
||
// Refetch balances when modal is opened | ||
useEffect(() => { | ||
if (isOpen) refetch(); | ||
}, [isOpen, refetch]); | ||
|
||
if (isFetching || !balances) { | ||
return <BalanceSpinner>Searching for balances...</BalanceSpinner>; | ||
} | ||
|
||
if (isPending) { | ||
return <BalanceSpinner>Refunding balances...</BalanceSpinner>; | ||
} | ||
|
||
const nonTrivialBalances = balances.filter((b) => b.amount >= MIN_DEPLOYER_BALANCE_TO_SHOW); | ||
const balanceChains = nonTrivialBalances | ||
.map((b) => getChainDisplayName(multiProvider, b.chainName)) | ||
.join(', '); | ||
|
||
if (!nonTrivialBalances.length) { | ||
return <div className="text-sm">No balances found on deployment chains</div>; | ||
} | ||
|
||
return ( | ||
<div className="flex flex-col items-center gap-2"> | ||
<span className="text-sm">{`Balances on found on chains: ${balanceChains}`}</span> | ||
<Button onClick={() => refund()} className="text-sm text-accent-500"> | ||
Refund balances | ||
</Button> | ||
</div> | ||
); | ||
} | ||
|
||
function BalanceSpinner({ children }: PropsWithChildren<unknown>) { | ||
return ( | ||
<div className="flex flex-col items-center justify-center gap-2"> | ||
<SpinnerIcon width={30} height={30} color={Color.primary['500']} /> | ||
<span className="text-sm text-gray-700">{children}</span> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { MultiProtocolProvider, Token } from '@hyperlane-xyz/sdk'; | ||
import { ProtocolType } from '@hyperlane-xyz/utils'; | ||
import { useQuery } from '@tanstack/react-query'; | ||
import { logger } from '../../utils/logger'; | ||
import { useMultiProvider } from '../chains/hooks'; | ||
import { useDeploymentChains } from '../deployment/hooks'; | ||
import { DeployerWallets } from './types'; | ||
|
||
export interface Balance { | ||
chainName: ChainName; | ||
protocol: ProtocolType; | ||
address: Address; | ||
amount: bigint; | ||
} | ||
|
||
export function useDeployerBalances(wallets: DeployerWallets) { | ||
const multiProvider = useMultiProvider(); | ||
const { chains } = useDeploymentChains(); | ||
|
||
const { data, isFetching, refetch } = useQuery({ | ||
// MultiProvider cannot be used here because it's not serializable | ||
// eslint-disable-next-line @tanstack/query/exhaustive-deps | ||
queryKey: ['getDeployerBalances', chains, wallets], | ||
queryFn: () => getDeployerBalances(chains, wallets, multiProvider), | ||
retry: 3, | ||
staleTime: 10_000, | ||
}); | ||
|
||
return { | ||
isFetching, | ||
balances: data, | ||
refetch, | ||
}; | ||
} | ||
|
||
export async function getDeployerBalances( | ||
chains: ChainName[], | ||
wallets: DeployerWallets, | ||
multiProvider: MultiProtocolProvider, | ||
) { | ||
const balances: Array<PromiseSettledResult<Balance | undefined>> = await Promise.allSettled( | ||
chains.map(async (chainName) => { | ||
try { | ||
const chainMetadata = multiProvider.tryGetChainMetadata(chainName); | ||
if (!chainMetadata) return undefined; | ||
const address = wallets[chainMetadata.protocol]?.address; | ||
if (!address) return undefined; | ||
const token = Token.FromChainMetadataNativeToken(chainMetadata); | ||
logger.debug('Checking balance', chainName, address); | ||
const balance = await token.getBalance(multiProvider, address); | ||
logger.debug('Balance retrieved', chainName, address, balance.amount); | ||
return { chainName, protocol: chainMetadata.protocol, address, amount: balance.amount }; | ||
} catch (error: unknown) { | ||
const msg = `Error getting balance for chain ${chainName}`; | ||
logger.error(msg, error); | ||
throw new Error(msg, { cause: error }); | ||
} | ||
}), | ||
); | ||
|
||
const nonZeroBalances = balances | ||
.filter((b) => b.status === 'fulfilled') | ||
.map((b) => b.value) | ||
.filter((b): b is Balance => !!b && b.amount > 0n); | ||
if (nonZeroBalances.length) { | ||
logger.debug( | ||
'Non-zero balances found for chains:', | ||
nonZeroBalances.map((b) => b.chainName).join(', '), | ||
); | ||
} | ||
|
||
return nonZeroBalances; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.