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:
parent
2ea41b8176
commit
d4b7dbf98b
|
@ -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;
|
|
@ -1,29 +1,31 @@
|
||||||
import { Typography } from "@material-ui/core";
|
import { useConnectedWallet, useWallet } from "@terra-money/wallet-provider";
|
||||||
import { useTerraWallet } from "../contexts/TerraWalletContext";
|
import { useCallback, useState } from "react";
|
||||||
|
import TerraConnectWalletDialog from "./TerraConnectWalletDialog";
|
||||||
import ToggleConnectedButton from "./ToggleConnectedButton";
|
import ToggleConnectedButton from "./ToggleConnectedButton";
|
||||||
|
|
||||||
const TerraWalletKey = () => {
|
const TerraWalletKey = () => {
|
||||||
const { connect, disconnect, connected, wallet, providerError } =
|
const wallet = useWallet();
|
||||||
useTerraWallet();
|
const connectedWallet = useConnectedWallet();
|
||||||
const pk =
|
|
||||||
(wallet &&
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||||
wallet.wallets &&
|
|
||||||
wallet.wallets.length > 0 &&
|
const connect = useCallback(() => {
|
||||||
wallet.wallets[0].terraAddress) ||
|
setIsDialogOpen(true);
|
||||||
"";
|
}, [setIsDialogOpen]);
|
||||||
|
|
||||||
|
const closeDialog = useCallback(() => {
|
||||||
|
setIsDialogOpen(false);
|
||||||
|
}, [setIsDialogOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ToggleConnectedButton
|
<ToggleConnectedButton
|
||||||
connect={connect}
|
connect={connect}
|
||||||
disconnect={disconnect}
|
disconnect={wallet.disconnect}
|
||||||
connected={connected}
|
connected={!!connectedWallet}
|
||||||
pk={pk}
|
pk={connectedWallet?.terraAddress || ""}
|
||||||
/>
|
/>
|
||||||
{providerError ? (
|
<TerraConnectWalletDialog isOpen={isDialogOpen} onClose={closeDialog} />
|
||||||
<Typography variant="body2" color="error">
|
|
||||||
{providerError}
|
|
||||||
</Typography>
|
|
||||||
) : null}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -72,7 +72,7 @@ export default function TransactionProgress({
|
||||||
tx && tx.block && currentBlock ? currentBlock - tx.block : undefined;
|
tx && tx.block && currentBlock ? currentBlock - tx.block : undefined;
|
||||||
const expectedBlocks =
|
const expectedBlocks =
|
||||||
chainId === CHAIN_ID_POLYGON
|
chainId === CHAIN_ID_POLYGON
|
||||||
? 256 // minimum confirmations enforced by guardians
|
? 512 // minimum confirmations enforced by guardians
|
||||||
: chainId === CHAIN_ID_SOLANA
|
: chainId === CHAIN_ID_SOLANA
|
||||||
? 32
|
? 32
|
||||||
: isEVMChain(chainId)
|
: isEVMChain(chainId)
|
||||||
|
|
|
@ -1,102 +1,24 @@
|
||||||
import {
|
import { NetworkInfo, WalletProvider } from "@terra-money/wallet-provider";
|
||||||
NetworkInfo,
|
import { ReactChildren } from "react";
|
||||||
Wallet,
|
import { CLUSTER } from "../utils/consts";
|
||||||
WalletProvider,
|
|
||||||
useWallet,
|
|
||||||
ConnectType,
|
|
||||||
} from "@terra-money/wallet-provider";
|
|
||||||
import React, {
|
|
||||||
ReactChildren,
|
|
||||||
useCallback,
|
|
||||||
useContext,
|
|
||||||
useMemo,
|
|
||||||
useState,
|
|
||||||
} from "react";
|
|
||||||
import { TERRA_HOST } from "../utils/consts";
|
|
||||||
|
|
||||||
const mainnet = {
|
const mainnet: NetworkInfo = {
|
||||||
name: "mainnet",
|
name: "mainnet",
|
||||||
chainID: "columbus-4",
|
chainID: "columbus-5",
|
||||||
lcd: "https://lcd.terra.dev",
|
lcd: "https://lcd.terra.dev",
|
||||||
};
|
};
|
||||||
|
|
||||||
const localnet = {
|
const testnet: NetworkInfo = {
|
||||||
name: "localnet",
|
name: "testnet",
|
||||||
chainID: "localnet",
|
chainID: "bombay-12",
|
||||||
lcd: TERRA_HOST.URL,
|
lcd: "https://bombay-lcd.terra.dev",
|
||||||
};
|
};
|
||||||
|
|
||||||
const walletConnectChainIds: Record<number, NetworkInfo> = {
|
const walletConnectChainIds: Record<number, NetworkInfo> = {
|
||||||
0: localnet,
|
0: testnet,
|
||||||
1: mainnet,
|
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 = ({
|
export const TerraWalletProvider = ({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
|
@ -104,14 +26,10 @@ export const TerraWalletProvider = ({
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<WalletProvider
|
<WalletProvider
|
||||||
defaultNetwork={localnet}
|
defaultNetwork={CLUSTER === "testnet" ? testnet : mainnet}
|
||||||
walletConnectChainIds={walletConnectChainIds}
|
walletConnectChainIds={walletConnectChainIds}
|
||||||
>
|
>
|
||||||
<TerraWalletWrapper>{children}</TerraWalletWrapper>
|
{children}
|
||||||
</WalletProvider>
|
</WalletProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useTerraWallet = () => {
|
|
||||||
return useContext(TerraWalletContext);
|
|
||||||
};
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {
|
||||||
CHAIN_ID_SOLANA,
|
CHAIN_ID_SOLANA,
|
||||||
CHAIN_ID_TERRA,
|
CHAIN_ID_TERRA,
|
||||||
isEVMChain,
|
isEVMChain,
|
||||||
|
isNativeDenom,
|
||||||
TokenImplementation__factory,
|
TokenImplementation__factory,
|
||||||
} from "@certusone/wormhole-sdk";
|
} from "@certusone/wormhole-sdk";
|
||||||
import { Connection, PublicKey } from "@solana/web3.js";
|
import { Connection, PublicKey } from "@solana/web3.js";
|
||||||
|
@ -18,6 +19,7 @@ import {
|
||||||
} from "../store/selectors";
|
} from "../store/selectors";
|
||||||
import { setTargetParsedTokenAccount } from "../store/transferSlice";
|
import { setTargetParsedTokenAccount } from "../store/transferSlice";
|
||||||
import { getEvmChainId, SOLANA_HOST, TERRA_HOST } from "../utils/consts";
|
import { getEvmChainId, SOLANA_HOST, TERRA_HOST } from "../utils/consts";
|
||||||
|
import { NATIVE_TERRA_DECIMALS } from "../utils/terra";
|
||||||
import { createParsedTokenAccount } from "./useGetSourceParsedTokenAccounts";
|
import { createParsedTokenAccount } from "./useGetSourceParsedTokenAccounts";
|
||||||
import useMetadata from "./useMetadata";
|
import useMetadata from "./useMetadata";
|
||||||
|
|
||||||
|
@ -56,6 +58,35 @@ function useGetTargetParsedTokenAccounts() {
|
||||||
|
|
||||||
if (targetChain === CHAIN_ID_TERRA && terraWallet) {
|
if (targetChain === CHAIN_ID_TERRA && terraWallet) {
|
||||||
const lcd = new LCDClient(TERRA_HOST);
|
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
|
lcd.wasm
|
||||||
.contractQuery(targetAsset, {
|
.contractQuery(targetAsset, {
|
||||||
token_info: {},
|
token_info: {},
|
||||||
|
@ -68,7 +99,7 @@ function useGetTargetParsedTokenAccounts() {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((balance: any) => {
|
.then((balance: any) => {
|
||||||
if (balance && info) {
|
if (balance && info && !cancelled) {
|
||||||
dispatch(
|
dispatch(
|
||||||
setTargetParsedTokenAccount(
|
setTargetParsedTokenAccount(
|
||||||
createParsedTokenAccount(
|
createParsedTokenAccount(
|
||||||
|
@ -86,7 +117,13 @@ function useGetTargetParsedTokenAccounts() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
.catch(() => {
|
||||||
|
if (!cancelled) {
|
||||||
|
// TODO: error state
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (targetChain === CHAIN_ID_SOLANA && solPK) {
|
if (targetChain === CHAIN_ID_SOLANA && solPK) {
|
||||||
let mint;
|
let mint;
|
||||||
|
|
Loading…
Reference in New Issue