bridge_ui: wrapped to wrapped

Change-Id: Icb12978ce7be6cc468d650039f508fc8ad19babe
This commit is contained in:
Evan Gray 2021-09-07 16:14:08 -04:00
parent a79ef81721
commit 42702dfbe8
8 changed files with 92 additions and 87 deletions

View File

@ -10,29 +10,32 @@ import {
} from "../../store/attestSlice";
import {
selectAttestSignedVAAHex,
selectTransferSourceAsset,
selectTransferSourceChain,
selectTransferOriginAsset,
selectTransferOriginChain,
selectTransferTargetChain,
} from "../../store/selectors";
import { hexToNativeString } from "../../utils/array";
export default function RegisterNowButton() {
const dispatch = useDispatch();
const history = useHistory();
const sourceChain = useSelector(selectTransferSourceChain);
const sourceAsset = useSelector(selectTransferSourceAsset);
const originChain = useSelector(selectTransferOriginChain);
const originAsset = useSelector(selectTransferOriginAsset);
const targetChain = useSelector(selectTransferTargetChain);
// user might be in the middle of a different attest
const signedVAAHex = useSelector(selectAttestSignedVAAHex);
const canSwitch = sourceAsset && !signedVAAHex;
const canSwitch = originChain && originAsset && !signedVAAHex;
const handleClick = useCallback(() => {
if (sourceAsset && canSwitch) {
dispatch(setSourceChain(sourceChain));
dispatch(setSourceAsset(sourceAsset));
const nativeAsset =
originChain && hexToNativeString(originAsset, originChain);
if (originChain && originAsset && nativeAsset && canSwitch) {
dispatch(setSourceChain(originChain));
dispatch(setSourceAsset(nativeAsset));
dispatch(setTargetChain(targetChain));
dispatch(setStep(2));
history.push("/register");
}
}, [dispatch, canSwitch, sourceChain, sourceAsset, targetChain, history]);
}, [dispatch, canSwitch, originChain, originAsset, targetChain, history]);
if (!canSwitch) return null;
return (
<Button

View File

@ -24,7 +24,7 @@ export const SolanaWalletProvider: FC = (props) => {
}, []);
return (
<WalletProvider wallets={wallets} autoConnect>
<WalletProvider wallets={wallets}>
<WalletDialogProvider>{props.children}</WalletDialogProvider>
</WalletProvider>
);

View File

@ -10,8 +10,6 @@ import {
selectTransferIsSourceAssetWormholeWrapped,
selectTransferOriginAsset,
selectTransferOriginChain,
selectTransferSourceAsset,
selectTransferSourceChain,
selectTransferTargetChain,
} from "../store/selectors";
import { setTargetAsset } from "../store/transferSlice";
@ -24,8 +22,6 @@ import {
function useFetchTargetAsset() {
const dispatch = useDispatch();
const sourceChain = useSelector(selectTransferSourceChain);
const sourceAsset = useSelector(selectTransferSourceAsset);
const isSourceAssetWormholeWrapped = useSelector(
selectTransferIsSourceAssetWormholeWrapped
);
@ -33,7 +29,6 @@ function useFetchTargetAsset() {
const originAsset = useSelector(selectTransferOriginAsset);
const targetChain = useSelector(selectTransferTargetChain);
const { provider } = useEthereumProvider();
// TODO: this may not cover wrapped to wrapped, should always use origin?
useEffect(() => {
if (isSourceAssetWormholeWrapped && originChain === targetChain) {
dispatch(setTargetAsset(hexToNativeString(originAsset, originChain)));
@ -43,19 +38,24 @@ function useFetchTargetAsset() {
dispatch(setTargetAsset(undefined));
let cancelled = false;
(async () => {
if (targetChain === CHAIN_ID_ETH && provider && sourceAsset) {
if (
targetChain === CHAIN_ID_ETH &&
provider &&
originChain &&
originAsset
) {
const asset = await getForeignAssetEth(
provider,
sourceChain,
sourceAsset
originChain,
originAsset
);
if (!cancelled) {
dispatch(setTargetAsset(asset));
}
}
if (targetChain === CHAIN_ID_SOLANA && sourceAsset) {
if (targetChain === CHAIN_ID_SOLANA && originChain && originAsset) {
try {
const asset = await getForeignAssetSol(sourceChain, sourceAsset);
const asset = await getForeignAssetSol(originChain, originAsset);
if (!cancelled) {
dispatch(setTargetAsset(asset));
}
@ -65,9 +65,9 @@ function useFetchTargetAsset() {
}
}
}
if (targetChain === CHAIN_ID_TERRA && sourceAsset) {
if (targetChain === CHAIN_ID_TERRA && originChain && originAsset) {
try {
const asset = await getForeignAssetTerra(sourceChain, sourceAsset);
const asset = await getForeignAssetTerra(originChain, originAsset);
if (!cancelled) {
dispatch(setTargetAsset(asset));
}
@ -87,8 +87,6 @@ function useFetchTargetAsset() {
originChain,
originAsset,
targetChain,
sourceChain,
sourceAsset,
provider,
]);
}

View File

@ -96,6 +96,7 @@ export const transferSlice = createSlice({
state.targetAddressHex = undefined;
// clear targetAsset so that components that fire before useFetchTargetAsset don't get stale data
state.targetAsset = undefined;
state.targetParsedTokenAccount = undefined;
}
},
setSourceWormholeWrappedInfo: (
@ -158,6 +159,7 @@ export const transferSlice = createSlice({
state.targetAddressHex = undefined;
// clear targetAsset so that components that fire before useFetchTargetAsset don't get stale data
state.targetAsset = undefined;
state.targetParsedTokenAccount = undefined;
if (state.sourceChain === action.payload) {
state.sourceChain = prevTargetChain;
state.activeStep = 0;
@ -196,6 +198,7 @@ export const transferSlice = createSlice({
},
setRedeemTx: (state, action: PayloadAction<Transaction>) => {
state.redeemTx = action.payload;
state.isRedeeming = false;
},
reset: (state) => ({
...initialState,

View File

@ -12,13 +12,17 @@ export const uint8ArrayToHex = (a: Uint8Array) =>
Buffer.from(a).toString("hex");
export const hexToUint8Array = (h: string) =>
new Uint8Array(Buffer.from(h, "hex"));
export const hexToNativeString = (h: string | undefined, c: ChainId) =>
!h
? undefined
: c === CHAIN_ID_SOLANA
? new PublicKey(hexToUint8Array(h)).toString()
: c === CHAIN_ID_ETH
? hexValue(hexToUint8Array(h))
: c === CHAIN_ID_TERRA
? humanAddress(hexToUint8Array(h.substr(24))) // terra expects 20 bytes, not 32
: h;
export const hexToNativeString = (h: string | undefined, c: ChainId) => {
try {
return !h
? undefined
: c === CHAIN_ID_SOLANA
? new PublicKey(hexToUint8Array(h)).toString()
: c === CHAIN_ID_ETH
? hexValue(hexToUint8Array(h))
: c === CHAIN_ID_TERRA
? humanAddress(hexToUint8Array(h.substr(24))) // terra expects 20 bytes, not 32
: h;
} catch (e) {}
return undefined;
};

View File

@ -1,19 +1,18 @@
import {
ChainId,
CHAIN_ID_SOLANA,
getForeignAssetEth as getForeignAssetEthTx,
getForeignAssetSolana as getForeignAssetSolanaTx,
getForeignAssetTerra as getForeignAssetTerraTx,
} from "@certusone/wormhole-sdk";
import { Connection, PublicKey } from "@solana/web3.js";
import { ethers } from "ethers";
import { arrayify, isHexString, zeroPad } from "ethers/lib/utils";
import { Connection } from "@solana/web3.js";
import { LCDClient } from "@terra-money/terra.js";
import { ethers } from "ethers";
import { hexToUint8Array } from "./array";
import {
ETH_TOKEN_BRIDGE_ADDRESS,
SOLANA_HOST,
TERRA_HOST,
SOL_TOKEN_BRIDGE_ADDRESS,
TERRA_HOST,
TERRA_TOKEN_BRIDGE_ADDRESS,
} from "./consts";
@ -23,21 +22,14 @@ export async function getForeignAssetEth(
originAsset: string
) {
try {
// TODO: address conversion may be more complex than this
const originAssetBytes = zeroPad(
originChain === CHAIN_ID_SOLANA
? new PublicKey(originAsset).toBytes()
: arrayify(originAsset),
32
);
return await getForeignAssetEthTx(
ETH_TOKEN_BRIDGE_ADDRESS,
provider,
originChain,
originAssetBytes
hexToUint8Array(originAsset)
);
} catch (e) {
return ethers.constants.AddressZero;
return null;
}
}
@ -45,18 +37,12 @@ export async function getForeignAssetSol(
originChain: ChainId,
originAsset: string
) {
if (!isHexString(originAsset)) return null;
// TODO: address conversion may be more complex than this
const originAssetBytes = zeroPad(
arrayify(originAsset, { hexPad: "left" }),
32
);
const connection = new Connection(SOLANA_HOST, "confirmed");
return await getForeignAssetSolanaTx(
connection,
SOL_TOKEN_BRIDGE_ADDRESS,
originChain,
originAssetBytes
hexToUint8Array(originAsset)
);
}
@ -71,21 +57,14 @@ export async function getForeignAssetTerra(
originAsset: string
) {
try {
const originAssetBytes = zeroPad(
originChain === CHAIN_ID_SOLANA
? new PublicKey(originAsset).toBytes()
: arrayify(originAsset),
32
);
const lcd = new LCDClient(TERRA_HOST);
return await getForeignAssetTerraTx(
TERRA_TOKEN_BRIDGE_ADDRESS,
lcd,
originChain,
originAssetBytes
hexToUint8Array(originAsset)
);
} catch (e) {
// TODO: better return for this
return ethers.constants.AddressZero;
return null;
}
}

View File

@ -23,7 +23,7 @@ export async function getForeignAssetEth(
try {
return await tokenBridge.wrappedAsset(originChain, originAsset);
} catch (e) {
return ethers.constants.AddressZero;
return null;
}
}
@ -33,13 +33,20 @@ export async function getForeignAssetTerra(
originChain: ChainId,
originAsset: Uint8Array
) {
const result: { address: string } = await client.wasm.contractQuery(tokenBridgeAddress, {
wrapped_registry: {
chain: originChain,
address: fromUint8Array(originAsset),
},
});
return result.address;
try {
const result: { address: string } = await client.wasm.contractQuery(
tokenBridgeAddress,
{
wrapped_registry: {
chain: originChain,
address: fromUint8Array(originAsset),
},
}
);
return result.address;
} catch (e) {
return null;
}
}
/**

View File

@ -51,7 +51,7 @@ export async function getOriginalAssetEth(
return {
isWrapped: false,
chainId: CHAIN_ID_ETH,
assetAddress: arrayify(wrappedAddress),
assetAddress: zeroPad(arrayify(wrappedAddress), 32),
};
}
@ -59,20 +59,24 @@ export async function getOriginalAssetTerra(
client: LCDClient,
wrappedAddress: string
): Promise<WormholeWrappedInfo> {
const result: {
asset_address: string;
asset_chain: ChainId;
bridge: string;
} = await client.wasm.contractQuery(wrappedAddress, {
wrapped_asset_info: {},
});
if (result) {
return {
isWrapped: true,
chainId: result.asset_chain,
assetAddress: new Uint8Array(Buffer.from(result.asset_address, "base64")),
};
}
try {
const result: {
asset_address: string;
asset_chain: ChainId;
bridge: string;
} = await client.wasm.contractQuery(wrappedAddress, {
wrapped_asset_info: {},
});
if (result) {
return {
isWrapped: true,
chainId: result.asset_chain,
assetAddress: new Uint8Array(
Buffer.from(result.asset_address, "base64")
),
};
}
} catch (e) {}
return {
isWrapped: false,
chainId: CHAIN_ID_TERRA,
@ -114,6 +118,13 @@ export async function getOriginalAssetSol(
};
}
}
try {
return {
isWrapped: false,
chainId: CHAIN_ID_SOLANA,
assetAddress: new PublicKey(mintAddress).toBytes(),
};
} catch (e) {}
return {
isWrapped: false,
chainId: CHAIN_ID_SOLANA,