wormhole/bridge_ui/src/hooks/useSyncTargetAddress.ts

111 lines
3.4 KiB
TypeScript

import {
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
} from "@certusone/wormhole-sdk";
import { arrayify, zeroPad } from "@ethersproject/bytes";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
Token,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import { PublicKey } from "@solana/web3.js";
import { useConnectedWallet } from "@terra-money/wallet-provider";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
import { useSolanaWallet } from "../contexts/SolanaWalletContext";
import {
selectTransferTargetAsset,
selectTransferTargetChain,
selectTransferTargetParsedTokenAccount,
} from "../store/selectors";
import { setTargetAddressHex } from "../store/transferSlice";
import { uint8ArrayToHex } from "../utils/array";
import bech32 from "bech32";
function useSyncTargetAddress(shouldFire: boolean) {
const dispatch = useDispatch();
const targetChain = useSelector(selectTransferTargetChain);
const { signerAddress } = useEthereumProvider();
const solanaWallet = useSolanaWallet();
const solPK = solanaWallet?.publicKey;
const targetAsset = useSelector(selectTransferTargetAsset);
const targetParsedTokenAccount = useSelector(
selectTransferTargetParsedTokenAccount
);
const targetTokenAccountPublicKey = targetParsedTokenAccount?.publicKey;
const terraWallet = useConnectedWallet();
useEffect(() => {
if (shouldFire) {
let cancelled = false;
if (targetChain === CHAIN_ID_ETH && signerAddress) {
dispatch(
setTargetAddressHex(
uint8ArrayToHex(zeroPad(arrayify(signerAddress), 32))
)
);
}
// TODO: have the user explicitly select an account on solana
else if (targetChain === CHAIN_ID_SOLANA && targetTokenAccountPublicKey) {
// use the target's TokenAccount if it exists
dispatch(
setTargetAddressHex(
uint8ArrayToHex(
zeroPad(new PublicKey(targetTokenAccountPublicKey).toBytes(), 32)
)
)
);
} else if (targetChain === CHAIN_ID_SOLANA && solPK && targetAsset) {
// otherwise, use the associated token account (which we create in the case it doesn't exist)
(async () => {
const associatedTokenAccount = await Token.getAssociatedTokenAddress(
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID,
new PublicKey(targetAsset),
solPK
);
if (!cancelled) {
dispatch(
setTargetAddressHex(
uint8ArrayToHex(zeroPad(associatedTokenAccount.toBytes(), 32))
)
);
}
})();
} else if (
targetChain === CHAIN_ID_TERRA &&
terraWallet &&
terraWallet.walletAddress
) {
dispatch(
setTargetAddressHex(
uint8ArrayToHex(
zeroPad(
new Uint8Array(bech32.decode(terraWallet.walletAddress).words),
32
)
)
)
);
} else {
dispatch(setTargetAddressHex(undefined));
}
return () => {
cancelled = true;
};
}
}, [
dispatch,
shouldFire,
targetChain,
signerAddress,
solPK,
targetAsset,
targetTokenAccountPublicKey,
terraWallet,
]);
}
export default useSyncTargetAddress;