bridge_ui: terra, terra transfers

Change-Id: I9a615bd69ed2cf82c9eccee304b1211fd0c9a96c
This commit is contained in:
Reisen 2021-08-19 12:21:41 +00:00
parent d09abac78f
commit 3795cb15fb
22 changed files with 397 additions and 15 deletions

View File

@ -12,7 +12,9 @@
"@solana/spl-token": "^0.1.6",
"@solana/wallet-base": "^0.0.1",
"@solana/web3.js": "^1.22.0",
"@terra-money/wallet-provider": "^1.4.0-alpha.1",
"ethers": "^5.4.1",
"js-base64": "^3.6.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.4",

View File

@ -1,6 +1,7 @@
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { CHAIN_ID_TERRA, CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { Button, CircularProgress, makeStyles } from "@material-ui/core";
import { useCallback } from "react";
import { useConnectedWallet } from "@terra-money/wallet-provider";
import { useDispatch, useSelector } from "react-redux";
import { useEthereumProvider } from "../../contexts/EthereumProviderContext";
import { useSolanaWallet } from "../../contexts/SolanaWalletContext";
@ -13,6 +14,7 @@ import {
import {
createWrappedOnEth,
createWrappedOnSolana,
createWrappedOnTerra,
} from "../../utils/createWrappedOn";
const useStyles = makeStyles((theme) => ({
@ -32,6 +34,7 @@ function Create() {
const signedVAA = useAttestSignedVAA();
const isCreating = useSelector(selectAttestIsCreating);
const { signer } = useEthereumProvider();
const terraWallet = useConnectedWallet();
const handleCreateClick = useCallback(() => {
if (targetChain === CHAIN_ID_SOLANA && signedVAA) {
(async () => {
@ -47,6 +50,12 @@ function Create() {
dispatch(reset());
})();
}
if (targetChain === CHAIN_ID_TERRA && signedVAA) {
(async () => {
dispatch(setIsCreating(true));
createWrappedOnTerra(terraWallet, signedVAA);
})();
}
}, [dispatch, targetChain, wallet, solPK, signedVAA, signer]);
return (
<div style={{ position: "relative" }}>

View File

@ -1,9 +1,10 @@
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { CHAIN_ID_TERRA, CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { Button, CircularProgress, makeStyles } from "@material-ui/core";
import { useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useEthereumProvider } from "../../contexts/EthereumProviderContext";
import { useSolanaWallet } from "../../contexts/SolanaWalletContext";
import { useConnectedWallet } from "@terra-money/wallet-provider";
import { setIsSending, setSignedVAAHex } from "../../store/attestSlice";
import {
selectAttestIsSendComplete,
@ -13,7 +14,11 @@ import {
selectAttestSourceChain,
} from "../../store/selectors";
import { uint8ArrayToHex } from "../../utils/array";
import { attestFromEth, attestFromSolana } from "../../utils/attestFrom";
import {
attestFromEth,
attestFromSolana,
attestFromTerra,
} from "../../utils/attestFrom";
const useStyles = makeStyles((theme) => ({
transferButton: {
@ -35,6 +40,7 @@ function Send() {
const isSendComplete = useSelector(selectAttestIsSendComplete);
const { signer } = useEthereumProvider();
const { wallet } = useSolanaWallet();
const terraWallet = useConnectedWallet();
const solPK = wallet?.publicKey;
// TODO: dynamically get "to" wallet
const handleAttestClick = useCallback(() => {
@ -68,7 +74,20 @@ function Send() {
dispatch(setIsSending(false));
}
})();
}
} else if (sourceChain === CHAIN_ID_TERRA) {
//TODO: just for testing, this should eventually use the store to communicate between steps
(async () => {
dispatch(setIsSending(true));
try {
const vaaBytes = await attestFromTerra(terraWallet, sourceAsset);
console.log("bytes in attest", vaaBytes);
vaaBytes && dispatch(setSignedVAAHex(uint8ArrayToHex(vaaBytes)));
} catch (e) {
console.error(e);
dispatch(setIsSending(false));
}
})();
}
}, [dispatch, sourceChain, signer, wallet, solPK, sourceAsset]);
return (
<>

View File

@ -2,10 +2,12 @@ import {
ChainId,
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
} from "@certusone/wormhole-sdk";
import { Typography } from "@material-ui/core";
import EthereumSignerKey from "./EthereumSignerKey";
import SolanaWalletKey from "./SolanaWalletKey";
import TerraWalletKey from "./TerraWalletKey";
function KeyAndBalance({
chainId,
@ -30,6 +32,14 @@ function KeyAndBalance({
</>
);
}
if (chainId === CHAIN_ID_TERRA) {
return (
<>
<TerraWalletKey />
<Typography>{balance}</Typography>
</>
);
}
return null;
}

View File

@ -0,0 +1,22 @@
import { useTerraWallet } from "../contexts/TerraWalletContext";
import ToggleConnectedButton from "./ToggleConnectedButton";
const TerraWalletKey = () => {
const { connect, disconnect, connected, wallet } = useTerraWallet();
const pk =
(wallet &&
wallet.wallets &&
wallet.wallets.length > 0 &&
wallet.wallets[0].terraAddress) ||
"";
return (
<ToggleConnectedButton
connect={connect}
disconnect={disconnect}
connected={connected}
pk={pk}
/>
);
};
export default TerraWalletKey;

View File

@ -1,7 +1,12 @@
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import {
CHAIN_ID_TERRA,
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
} from "@certusone/wormhole-sdk";
import { Button, CircularProgress, makeStyles } from "@material-ui/core";
import { useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useConnectedWallet } from "@terra-money/wallet-provider";
import { useEthereumProvider } from "../../contexts/EthereumProviderContext";
import { useSolanaWallet } from "../../contexts/SolanaWalletContext";
import useTransferSignedVAA from "../../hooks/useTransferSignedVAA";
@ -13,7 +18,11 @@ import {
selectTransferTargetChain,
} from "../../store/selectors";
import { reset, setIsRedeeming } from "../../store/transferSlice";
import { redeemOnEth, redeemOnSolana } from "../../utils/redeemOn";
import {
redeemOnEth,
redeemOnSolana,
redeemOnTerra,
} from "../../utils/redeemOn";
const useStyles = makeStyles((theme) => ({
transferButton: {
@ -35,6 +44,7 @@ function Redeem() {
const { wallet } = useSolanaWallet();
const solPK = wallet?.publicKey;
const { signer } = useEthereumProvider();
const terraWallet = useConnectedWallet();
const signedVAA = useTransferSignedVAA();
const isRedeeming = useSelector(selectTransferIsRedeeming);
const handleRedeemClick = useCallback(() => {
@ -58,8 +68,13 @@ function Redeem() {
dispatch(reset());
})();
}
if (targetChain === CHAIN_ID_TERRA && signedVAA) {
dispatch(setIsRedeeming(true));
redeemOnTerra(terraWallet, signedVAA);
}
}, [
dispatch,
terraWallet,
targetChain,
signer,
signedVAA,

View File

@ -1,4 +1,4 @@
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { CHAIN_ID_TERRA, CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { Button, CircularProgress, makeStyles } from "@material-ui/core";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
@ -27,7 +27,11 @@ import {
} from "../../store/selectors";
import { setIsSending, setSignedVAAHex } from "../../store/transferSlice";
import { uint8ArrayToHex } from "../../utils/array";
import { transferFromEth, transferFromSolana } from "../../utils/transferFrom";
import {
transferFromEth,
transferFromSolana,
transferFromTerra,
} from "../../utils/transferFrom";
const useStyles = makeStyles((theme) => ({
transferButton: {
@ -146,6 +150,19 @@ function Send() {
}
})();
}
if (sourceChain === CHAIN_ID_TERRA && decimals) {
(async () => {
dispatch(setIsSending(true));
try {
const vaaBytes = await transferFromTerra(undefined);
console.log("bytes in transfer", vaaBytes);
vaaBytes && dispatch(setSignedVAAHex(uint8ArrayToHex(vaaBytes)));
} catch (e) {
console.error(e);
dispatch(setIsSending(false));
}
})();
}
}, [
dispatch,
sourceChain,

View File

@ -29,9 +29,11 @@ function Transfer() {
useCheckIfWormholeWrapped();
useFetchTargetAsset();
useGetBalanceEffect("target");
const dispatch = useDispatch();
const activeStep = useSelector(selectTransferActiveStep);
const signedVAAHex = useSelector(selectTransferSignedVAAHex);
return (
<Container maxWidth="md">
<Stepper activeStep={activeStep} orientation="vertical">

View File

@ -0,0 +1,105 @@
import {
NetworkInfo,
Wallet,
WalletProvider,
useWallet,
} from "@terra-money/wallet-provider";
import React, {
ReactChildren,
useCallback,
useContext,
useMemo,
useState,
} from "react";
import { TERRA_HOST } from "../utils/consts";
const mainnet = {
name: "mainnet",
chainID: "columbus-4",
lcd: "https://lcd.terra.dev",
};
const localnet = {
name: "localnet",
chainID: "localnet",
lcd: TERRA_HOST,
};
const walletConnectChainIds: Record<number, NetworkInfo> = {
0: localnet,
1: mainnet,
};
interface ITerraWalletContext {
connect(): void;
disconnect(): void;
connected: boolean;
wallet: any;
}
const TerraWalletContext = React.createContext<ITerraWalletContext>({
connect: () => {},
disconnect: () => {},
connected: false,
wallet: null,
});
export const TerraWalletWrapper = ({
children,
}: {
children: ReactChildren;
}) => {
// TODO: Use wallet instead of useConnectedWallet.
const terraWallet = useWallet();
const [wallet, setWallet] = useState<Wallet | undefined>(undefined);
const [connected, setConnected] = useState(false);
const connect = useCallback(() => {
const CHROME_EXTENSION = 1;
if (terraWallet) {
terraWallet.connect(terraWallet.availableConnectTypes[CHROME_EXTENSION]);
setWallet(terraWallet);
setConnected(true);
}
}, [terraWallet]);
const disconnect = useCallback(() => {
setConnected(false);
setWallet(undefined);
}, []);
const contextValue = useMemo(
() => ({
connect,
disconnect,
connected,
wallet: terraWallet,
}),
[connect, disconnect, connected, terraWallet]
);
return (
<TerraWalletContext.Provider value={contextValue}>
{children}
</TerraWalletContext.Provider>
);
};
export const TerraWalletProvider = ({
children,
}: {
children: ReactChildren;
}) => {
return (
<WalletProvider
defaultNetwork={localnet}
walletConnectChainIds={walletConnectChainIds}
>
<TerraWalletWrapper>{children}</TerraWalletWrapper>
</WalletProvider>
);
};
export const useTerraWallet = () => {
return useContext(TerraWalletContext);
};

View File

@ -1,4 +1,4 @@
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA, CHAIN_ID_TERRA } from "@certusone/wormhole-sdk";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
@ -10,8 +10,12 @@ import { setSourceWormholeWrappedInfo } from "../store/transferSlice";
import {
getOriginalAssetEth,
getOriginalAssetSol,
getOriginalAssetTerra,
} from "../utils/getOriginalAsset";
// Check if the tokens in the configured source chain/address are wrapped
// tokens. Wrapped tokens are tokens that are non-native, I.E, are locked up on
// a different chain than this one.
function useCheckIfWormholeWrapped() {
const dispatch = useDispatch();
const sourceChain = useSelector(selectTransferSourceChain);
@ -27,7 +31,8 @@ function useCheckIfWormholeWrapped() {
if (!cancelled) {
dispatch(setSourceWormholeWrappedInfo(wrappedInfo));
}
} else if (sourceChain === CHAIN_ID_SOLANA) {
}
if (sourceChain === CHAIN_ID_SOLANA) {
try {
const wrappedInfo = await getOriginalAssetSol(sourceAsset);
if (!cancelled) {
@ -35,6 +40,14 @@ function useCheckIfWormholeWrapped() {
}
} catch (e) {}
}
if (sourceChain === CHAIN_ID_TERRA) {
try {
const wrappedInfo = await getOriginalAssetTerra(sourceAsset);
if (!cancelled) {
dispatch(setSourceWormholeWrappedInfo(wrappedInfo));
}
} catch (e) {}
}
})();
return () => {
cancelled = true;

View File

@ -1,4 +1,4 @@
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { CHAIN_ID_TERRA, CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useEthereumProvider } from "../contexts/EthereumProviderContext";
@ -14,6 +14,7 @@ import { setTargetAsset } from "../store/transferSlice";
import {
getForeignAssetEth,
getForeignAssetSol,
getForeignAssetTerra,
} from "../utils/getForeignAsset";
function useFetchTargetAsset() {
@ -51,7 +52,8 @@ function useFetchTargetAsset() {
if (!cancelled) {
dispatch(setTargetAsset(asset));
}
} else if (targetChain === CHAIN_ID_SOLANA) {
}
if (targetChain === CHAIN_ID_SOLANA) {
try {
const asset = await getForeignAssetSol(sourceChain, sourceAsset);
if (!cancelled) {
@ -64,6 +66,19 @@ function useFetchTargetAsset() {
}
}
}
if (targetChain === CHAIN_ID_TERRA) {
try {
const asset = await getForeignAssetTerra(sourceChain, sourceAsset);
if (!cancelled) {
console.log("terra target asset", asset);
dispatch(setTargetAsset(asset));
}
} catch (e) {
if (!cancelled) {
// TODO: warning for this
}
}
}
})();
return () => {
cancelled = true;

View File

@ -1,6 +1,7 @@
import {
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
TokenImplementation__factory,
} from "@certusone/wormhole-sdk";
import { Connection, PublicKey } from "@solana/web3.js";
@ -68,6 +69,13 @@ function useGetBalanceEffect(sourceOrTarget: "source" | "target") {
return;
}
let cancelled = false;
if (lookupChain === CHAIN_ID_TERRA && wallet) {
dispatch(
setSourceParsedTokenAccount(
createParsedTokenAccount(undefined, "0", 0, 0, "0")
)
);
}
if (lookupChain === CHAIN_ID_SOLANA && solPK) {
let mint;
try {
@ -143,6 +151,7 @@ function useGetBalanceEffect(sourceOrTarget: "source" | "target") {
};
}, [
dispatch,
wallet,
sourceOrTarget,
setAction,
lookupChain,

View File

@ -7,6 +7,7 @@ import App from "./App";
import RadialGradient from "./components/RadialGradient";
import { EthereumProviderProvider } from "./contexts/EthereumProviderContext";
import { SolanaWalletProvider } from "./contexts/SolanaWalletContext.tsx";
import { TerraWalletProvider } from "./contexts/TerraWalletContext.tsx";
import { theme } from "./muiTheme";
import { store } from "./store";
@ -17,9 +18,11 @@ ReactDOM.render(
<RadialGradient />
<SolanaWalletProvider>
<EthereumProviderProvider>
<HashRouter>
<App />
</HashRouter>
<TerraWalletProvider>
<HashRouter>
<App />
</HashRouter>
</TerraWalletProvider>
</EthereumProviderProvider>
</SolanaWalletProvider>
</ThemeProvider>

View File

@ -2,11 +2,13 @@ import {
ChainId,
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
} from "@certusone/wormhole-sdk";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import {
ETH_TEST_TOKEN_ADDRESS,
SOL_TEST_TOKEN_ADDRESS,
TERRA_TEST_TOKEN_ADDRESS,
} from "../utils/consts";
const LAST_STEP = 3;
@ -56,6 +58,9 @@ export const attestSlice = createSlice({
if (action.payload === CHAIN_ID_SOLANA) {
state.sourceAsset = SOL_TEST_TOKEN_ADDRESS;
}
if (action.payload === CHAIN_ID_TERRA) {
state.sourceAsset = TERRA_TEST_TOKEN_ADDRESS;
}
if (state.targetChain === action.payload) {
state.targetChain = prevSourceChain;
}
@ -76,6 +81,9 @@ export const attestSlice = createSlice({
if (state.targetChain === CHAIN_ID_SOLANA) {
state.sourceAsset = SOL_TEST_TOKEN_ADDRESS;
}
if (state.targetChain === CHAIN_ID_TERRA) {
state.sourceAsset = TERRA_TEST_TOKEN_ADDRESS;
}
}
},
setSignedVAAHex: (state, action: PayloadAction<string>) => {

View File

@ -2,11 +2,13 @@ import {
ChainId,
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
} from "@certusone/wormhole-sdk";
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import {
ETH_TEST_TOKEN_ADDRESS,
SOL_TEST_TOKEN_ADDRESS,
TERRA_TEST_TOKEN_ADDRESS,
} from "../utils/consts";
import { StateSafeWormholeWrappedInfo } from "../utils/getOriginalAsset";
@ -79,6 +81,9 @@ export const transferSlice = createSlice({
if (action.payload === CHAIN_ID_SOLANA) {
state.sourceAsset = SOL_TEST_TOKEN_ADDRESS;
}
if (action.payload === CHAIN_ID_TERRA) {
state.sourceAsset = TERRA_TEST_TOKEN_ADDRESS;
}
if (state.targetChain === action.payload) {
state.targetChain = prevSourceChain;
}
@ -122,6 +127,9 @@ export const transferSlice = createSlice({
if (state.targetChain === CHAIN_ID_SOLANA) {
state.sourceAsset = SOL_TEST_TOKEN_ADDRESS;
}
if (state.targetChain === CHAIN_ID_TERRA) {
state.sourceAsset = TERRA_TEST_TOKEN_ADDRESS;
}
}
},
setTargetAsset: (

View File

@ -3,6 +3,7 @@ import {
attestFromSolana as attestSolanaTx,
CHAIN_ID_ETH,
CHAIN_ID_SOLANA,
CHAIN_ID_TERRA,
getEmitterAddressEth,
getEmitterAddressSolana,
parseSequenceFromLogEth,
@ -10,10 +11,13 @@ import {
} from "@certusone/wormhole-sdk";
import Wallet from "@project-serum/sol-wallet-adapter";
import { Connection } from "@solana/web3.js";
import { MsgExecuteContract } from "@terra-money/terra.js";
import { ConnectedWallet as TerraConnectedWallet } from "@terra-money/wallet-provider";
import { ethers } from "ethers";
import {
ETH_BRIDGE_ADDRESS,
ETH_TOKEN_BRIDGE_ADDRESS,
TERRA_TOKEN_BRIDGE_ADDRESS,
SOLANA_HOST,
SOL_BRIDGE_ADDRESS,
SOL_TOKEN_BRIDGE_ADDRESS,
@ -71,3 +75,29 @@ export async function attestFromSolana(
);
return vaaBytes;
}
export async function attestFromTerra(
wallet: TerraConnectedWallet | undefined,
asset: string | undefined
) {
const nonceConst = Math.random() * 100000;
const nonceBuffer = Buffer.alloc(4);
nonceBuffer.writeUInt32LE(nonceConst, 0);
wallet &&
(await wallet.post({
msgs: [
new MsgExecuteContract(
wallet.terraAddress,
TERRA_TOKEN_BRIDGE_ADDRESS,
{
register_asset_hook: {
asset_id: asset,
},
},
{ uluna: 1000 }
),
],
memo: "Create Wrapped",
}));
return null;
}

View File

@ -36,6 +36,7 @@ export const CHAINS_BY_ID: ChainsById = CHAINS.reduce((obj, chain) => {
}, {} as ChainsById);
export const WORMHOLE_RPC_HOST = "http://localhost:8080";
export const SOLANA_HOST = "http://localhost:8899";
export const TERRA_HOST = "http://localhost:1317";
export const ETH_TEST_TOKEN_ADDRESS = getAddress(
"0x67B5656d60a809915323Bf2C40A8bEF15A152e3e"
);
@ -50,3 +51,9 @@ export const SOL_TEST_TOKEN_ADDRESS =
export const SOL_BRIDGE_ADDRESS = "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o";
export const SOL_TOKEN_BRIDGE_ADDRESS =
"B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE";
export const TERRA_TEST_TOKEN_ADDRESS =
"terra13nkgqrfymug724h8pprpexqj9h629sa3ncw7sh";
export const TERRA_BRIDGE_ADDRESS =
"terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5";
export const TERRA_TOKEN_BRIDGE_ADDRESS =
"terra10pyejy66429refv3g35g2t7am0was7ya7kz2a4";

View File

@ -6,11 +6,16 @@ import {
import Wallet from "@project-serum/sol-wallet-adapter";
import { Connection } from "@solana/web3.js";
import { ethers } from "ethers";
import { fromUint8Array } from "js-base64";
import { MsgExecuteContract } from "@terra-money/terra.js";
import { ConnectedWallet as TerraConnectedWallet } from "@terra-money/wallet-provider";
import {
ETH_TOKEN_BRIDGE_ADDRESS,
SOLANA_HOST,
SOL_BRIDGE_ADDRESS,
SOL_TOKEN_BRIDGE_ADDRESS,
TERRA_TOKEN_BRIDGE_ADDRESS,
TERRA_BRIDGE_ADDRESS,
} from "./consts";
import { signSendAndConfirm } from "./solana";
@ -22,6 +27,32 @@ export async function createWrappedOnEth(
await createWrappedOnEthTx(ETH_TOKEN_BRIDGE_ADDRESS, signer, signedVAA);
}
export async function createWrappedOnTerra(
wallet: TerraConnectedWallet | undefined,
signedVAA: Uint8Array
) {
console.log("creating wrapped");
console.log("PROGRAM:", TERRA_TOKEN_BRIDGE_ADDRESS);
console.log("BRIDGE:", TERRA_BRIDGE_ADDRESS);
console.log("VAA:", signedVAA);
wallet &&
(await wallet.post({
msgs: [
new MsgExecuteContract(
wallet.terraAddress,
TERRA_TOKEN_BRIDGE_ADDRESS,
{
submit_vaa: {
data: fromUint8Array(signedVAA),
},
},
{ uluna: 1000 }
),
],
memo: "Create Wrapped",
}));
}
export async function createWrappedOnSolana(
wallet: Wallet | undefined,
payerAddress: string | undefined, //TODO: we may not need this since we have wallet

View File

@ -56,3 +56,16 @@ export async function getForeignAssetSol(
originAssetBytes
);
}
/**
* Returns a foreign asset address on Terra for a provided native chain and asset address
* @param originChain
* @param originAsset
* @returns
*/
export async function getForeignAssetTerra(
originChain: ChainId,
originAsset: string
) {
return null;
}

View File

@ -52,3 +52,13 @@ export async function getOriginalAssetSol(
)
);
}
export async function getOriginalAssetTerra(
mintAddress: string
): Promise<StateSafeWormholeWrappedInfo> {
return {
assetAddress: "",
chainId: 3,
isWrapped: false,
};
}

View File

@ -6,11 +6,15 @@ import {
import Wallet from "@project-serum/sol-wallet-adapter";
import { Connection } from "@solana/web3.js";
import { ethers } from "ethers";
import { fromUint8Array } from 'js-base64';
import { ConnectedWallet as TerraConnectedWallet } from "@terra-money/wallet-provider";
import { MsgExecuteContract } from "@terra-money/terra.js";
import {
ETH_TOKEN_BRIDGE_ADDRESS,
SOLANA_HOST,
SOL_BRIDGE_ADDRESS,
SOL_TOKEN_BRIDGE_ADDRESS,
TERRA_TOKEN_BRIDGE_ADDRESS,
} from "./consts";
import { signSendAndConfirm } from "./solana";
@ -50,3 +54,25 @@ export async function redeemOnSolana(
);
await signSendAndConfirm(wallet, connection, transaction);
}
export async function redeemOnTerra(
wallet: TerraConnectedWallet | undefined,
signedVAA: Uint8Array,
) {
if (!wallet) return;
wallet && await wallet.post({
msgs: [
new MsgExecuteContract(
wallet.terraAddress,
TERRA_TOKEN_BRIDGE_ADDRESS,
{
submit_vaa: {
data: fromUint8Array(signedVAA)
},
},
{ uluna: 1000 }
),
],
memo: "Complete Transfer",
});
}

View File

@ -1,6 +1,7 @@
import {
ChainId,
CHAIN_ID_ETH,
CHAIN_ID_TERRA,
CHAIN_ID_SOLANA,
getEmitterAddressEth,
getEmitterAddressSolana,
@ -9,6 +10,7 @@ import {
transferFromEth as transferFromEthTx,
transferFromSolana as transferFromSolanaTx,
} from "@certusone/wormhole-sdk";
import { Wallet as TerraWallet } from "@terra-money/wallet-provider";
import Wallet from "@project-serum/sol-wallet-adapter";
import { Connection } from "@solana/web3.js";
import { ethers } from "ethers";
@ -110,3 +112,9 @@ export async function transferFromSolana(
);
return vaaBytes;
}
export async function transferFromTerra(
wallet: TerraWallet | undefined,
) {
return null;
}