bridge_ui: xdefi and leap wallet support (#866)

* bridge_ui: xdefi and leap wallet support

* bridge_ui: wallet connect feature refactor

* bridge_ui: terra native balance fix

* bridge_ui: bumped max polygon confirmations to 512
This commit is contained in:
kev1n-peters 2022-02-23 22:52:02 -06:00 committed by GitHub
parent 2ea41b8176
commit d4b7dbf98b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 226 additions and 143 deletions

View File

@ -0,0 +1,126 @@
import {
Dialog,
DialogTitle,
IconButton,
List,
ListItem,
ListItemIcon,
ListItemText,
makeStyles,
} from "@material-ui/core";
import CloseIcon from "@material-ui/icons/Close";
import { ConnectType, useWallet } from "@terra-money/wallet-provider";
import { useCallback } from "react";
const useStyles = makeStyles((theme) => ({
flexTitle: {
display: "flex",
alignItems: "center",
"& > div": {
flexGrow: 1,
marginRight: theme.spacing(4),
},
"& > button": {
marginRight: theme.spacing(-1),
},
},
icon: {
height: 24,
width: 24,
},
}));
const WalletOptions = ({
type,
identifier,
connect,
onClose,
icon,
name,
}: {
type: ConnectType;
identifier: string;
connect: (
type: ConnectType | undefined,
identifier: string | undefined
) => void;
onClose: () => void;
icon: string;
name: string;
}) => {
const classes = useStyles();
const handleClick = useCallback(() => {
connect(type, identifier);
onClose();
}, [connect, onClose, type, identifier]);
return (
<ListItem button onClick={handleClick}>
<ListItemIcon>
<img src={icon} alt={name} className={classes.icon} />
</ListItemIcon>
<ListItemText>{name}</ListItemText>
</ListItem>
);
};
const TerraConnectWalletDialog = ({
isOpen,
onClose,
}: {
isOpen: boolean;
onClose: () => void;
}) => {
const { availableConnections, availableInstallations, connect } = useWallet();
const classes = useStyles();
const filteredConnections = availableConnections
.filter(({ type }) => type !== ConnectType.READONLY)
.map(({ type, name, icon, identifier = "" }) => (
<WalletOptions
type={type}
identifier={identifier}
connect={connect}
onClose={onClose}
icon={icon}
name={name}
key={"connection-" + type + identifier}
/>
));
const filteredInstallations = availableInstallations
.filter(({ type }) => type !== ConnectType.READONLY)
.map(({ type, name, icon, url, identifier = "" }) => (
<ListItem
button
component="a"
key={"install-" + type + identifier}
href={url}
target="_blank"
rel="noreferrer"
>
<ListItemIcon>
<img src={icon} alt={name} className={classes.icon} />
</ListItemIcon>
<ListItemText>{"Install " + name}</ListItemText>
</ListItem>
));
return (
<Dialog open={isOpen} onClose={onClose}>
<DialogTitle>
<div className={classes.flexTitle}>
<div>Select your wallet</div>
<IconButton onClick={onClose}>
<CloseIcon />
</IconButton>
</div>
</DialogTitle>
<List>
{filteredConnections}
{filteredInstallations}
</List>
</Dialog>
);
};
export default TerraConnectWalletDialog;

View File

@ -1,29 +1,31 @@
import { Typography } from "@material-ui/core";
import { useTerraWallet } from "../contexts/TerraWalletContext";
import { useConnectedWallet, useWallet } from "@terra-money/wallet-provider";
import { useCallback, useState } from "react";
import TerraConnectWalletDialog from "./TerraConnectWalletDialog";
import ToggleConnectedButton from "./ToggleConnectedButton";
const TerraWalletKey = () => {
const { connect, disconnect, connected, wallet, providerError } =
useTerraWallet();
const pk =
(wallet &&
wallet.wallets &&
wallet.wallets.length > 0 &&
wallet.wallets[0].terraAddress) ||
"";
const wallet = useWallet();
const connectedWallet = useConnectedWallet();
const [isDialogOpen, setIsDialogOpen] = useState(false);
const connect = useCallback(() => {
setIsDialogOpen(true);
}, [setIsDialogOpen]);
const closeDialog = useCallback(() => {
setIsDialogOpen(false);
}, [setIsDialogOpen]);
return (
<>
<ToggleConnectedButton
connect={connect}
disconnect={disconnect}
connected={connected}
pk={pk}
disconnect={wallet.disconnect}
connected={!!connectedWallet}
pk={connectedWallet?.terraAddress || ""}
/>
{providerError ? (
<Typography variant="body2" color="error">
{providerError}
</Typography>
) : null}
<TerraConnectWalletDialog isOpen={isDialogOpen} onClose={closeDialog} />
</>
);
};

View File

@ -72,7 +72,7 @@ export default function TransactionProgress({
tx && tx.block && currentBlock ? currentBlock - tx.block : undefined;
const expectedBlocks =
chainId === CHAIN_ID_POLYGON
? 256 // minimum confirmations enforced by guardians
? 512 // minimum confirmations enforced by guardians
: chainId === CHAIN_ID_SOLANA
? 32
: isEVMChain(chainId)

View File

@ -1,102 +1,24 @@
import {
NetworkInfo,
Wallet,
WalletProvider,
useWallet,
ConnectType,
} from "@terra-money/wallet-provider";
import React, {
ReactChildren,
useCallback,
useContext,
useMemo,
useState,
} from "react";
import { TERRA_HOST } from "../utils/consts";
import { NetworkInfo, WalletProvider } from "@terra-money/wallet-provider";
import { ReactChildren } from "react";
import { CLUSTER } from "../utils/consts";
const mainnet = {
const mainnet: NetworkInfo = {
name: "mainnet",
chainID: "columbus-4",
chainID: "columbus-5",
lcd: "https://lcd.terra.dev",
};
const localnet = {
name: "localnet",
chainID: "localnet",
lcd: TERRA_HOST.URL,
const testnet: NetworkInfo = {
name: "testnet",
chainID: "bombay-12",
lcd: "https://bombay-lcd.terra.dev",
};
const walletConnectChainIds: Record<number, NetworkInfo> = {
0: localnet,
0: testnet,
1: mainnet,
};
interface ITerraWalletContext {
connect(): void;
disconnect(): void;
connected: boolean;
wallet: any;
providerError: string | null;
}
const TerraWalletContext = React.createContext<ITerraWalletContext>({
connect: () => {},
disconnect: () => {},
connected: false,
wallet: null,
providerError: null,
});
export const TerraWalletWrapper = ({
children,
}: {
children: ReactChildren;
}) => {
// TODO: Use wallet instead of useConnectedWallet.
const terraWallet = useWallet();
const [, setWallet] = useState<Wallet | undefined>(undefined);
const [connected, setConnected] = useState(false);
const [providerError, setProviderError] = useState<string | null>(null);
const connect = useCallback(() => {
if (terraWallet) {
// TODO: Support other connect types
if (terraWallet.availableConnectTypes.includes(ConnectType.EXTENSION)) {
terraWallet.connect(ConnectType.EXTENSION);
setConnected(true);
setProviderError(null);
} else {
setConnected(false);
setProviderError("Please install the Terra Station Extension");
}
setWallet(terraWallet);
}
}, [terraWallet]);
const disconnect = useCallback(() => {
setConnected(false);
setWallet(undefined);
setProviderError(null);
}, []);
const contextValue = useMemo(
() => ({
connect,
disconnect,
connected,
wallet: terraWallet,
providerError,
}),
[connect, disconnect, connected, terraWallet, providerError]
);
return (
<TerraWalletContext.Provider value={contextValue}>
{children}
</TerraWalletContext.Provider>
);
};
export const TerraWalletProvider = ({
children,
}: {
@ -104,14 +26,10 @@ export const TerraWalletProvider = ({
}) => {
return (
<WalletProvider
defaultNetwork={localnet}
defaultNetwork={CLUSTER === "testnet" ? testnet : mainnet}
walletConnectChainIds={walletConnectChainIds}
>
<TerraWalletWrapper>{children}</TerraWalletWrapper>
{children}
</WalletProvider>
);
};
export const useTerraWallet = () => {
return useContext(TerraWalletContext);
};

View File

@ -2,6 +2,7 @@ import {
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
isEVMChain,
isNativeDenom,
TokenImplementation__factory,
} from "@certusone/wormhole-sdk";
import { Connection, PublicKey } from "@solana/web3.js";
@ -18,6 +19,7 @@ import {
} from "../store/selectors";
import { setTargetParsedTokenAccount } from "../store/transferSlice";
import { getEvmChainId, SOLANA_HOST, TERRA_HOST } from "../utils/consts";
import { NATIVE_TERRA_DECIMALS } from "../utils/terra";
import { createParsedTokenAccount } from "./useGetSourceParsedTokenAccounts";
import useMetadata from "./useMetadata";
@ -56,6 +58,35 @@ function useGetTargetParsedTokenAccounts() {
if (targetChain === CHAIN_ID_TERRA && terraWallet) {
const lcd = new LCDClient(TERRA_HOST);
if (isNativeDenom(targetAsset)) {
lcd.bank
.balance(terraWallet.walletAddress)
.then(([coins]) => {
const balance = coins.get(targetAsset)?.amount?.toString();
if (balance && !cancelled) {
dispatch(
setTargetParsedTokenAccount(
createParsedTokenAccount(
"",
"",
balance,
NATIVE_TERRA_DECIMALS,
Number(formatUnits(balance, NATIVE_TERRA_DECIMALS)),
formatUnits(balance, NATIVE_TERRA_DECIMALS),
symbol,
tokenName,
logo
)
)
);
}
})
.catch(() => {
if (!cancelled) {
// TODO: error state
}
});
} else {
lcd.wasm
.contractQuery(targetAsset, {
token_info: {},
@ -68,7 +99,7 @@ function useGetTargetParsedTokenAccounts() {
},
})
.then((balance: any) => {
if (balance && info) {
if (balance && info && !cancelled) {
dispatch(
setTargetParsedTokenAccount(
createParsedTokenAccount(
@ -86,7 +117,13 @@ function useGetTargetParsedTokenAccounts() {
);
}
})
);
)
.catch(() => {
if (!cancelled) {
// TODO: error state
}
});
}
}
if (targetChain === CHAIN_ID_SOLANA && solPK) {
let mint;