Working sol -> eth wormhole (#87)

* Workin sol -> eth wormhole

* remove console

* fixed selecting same chains and showing same balances
This commit is contained in:
Juan Diego García 2021-04-22 19:52:18 -05:00 committed by GitHub
parent dce6790f4e
commit 2fddc4d024
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 457 additions and 183 deletions

View File

@ -28,24 +28,6 @@ export function Input(props: {
}) {
const { connected } = useWallet();
const [lastAmount, setLastAmount] = useState<string>('');
const { userAccounts } = useUserAccounts();
const [balance, setBalance] = useState<number>(0);
const mint = useMint(props.asset?.startsWith('0x') ? '' : props.asset);
useEffect(() => {
if (props.chain === ASSET_CHAIN.Solana) {
const currentAccount = userAccounts?.find(
a => a.info.mint.toBase58() === props.asset,
);
if (currentAccount && mint) {
setBalance(
currentAccount.info.amount.toNumber() / Math.pow(10, mint.decimals),
);
} else {
setBalance(0);
}
}
}, [props.asset, props.chain, userAccounts, mint]);
return (
<div className={`dashed-input-container ${props.className}`}>
@ -53,25 +35,14 @@ export function Input(props: {
<div className="input-chain">
<TokenChain chain={props.chain} className={'input-icon'} />
{chainToName(props.chain)}
{props.chain !== ASSET_CHAIN.Solana ? (
typeof props.balance === 'number' && (
<div
className="balance"
onClick={() =>
props.onInputChange && props.onInputChange(props.balance)
}
>
{props.balance.toFixed(10)}
</div>
)
) : (
<div
className="balance"
onClick={() => props.onInputChange && props.onInputChange(balance)}
>
{balance.toFixed(10)}
</div>
)}
<div
className="balance"
onClick={() =>
props.onInputChange && props.onInputChange(props.balance)
}
>
{props.balance}
</div>
</div>
<div className="input-container">
<NumericInput

View File

@ -1,5 +1,5 @@
import { Table } from 'antd';
import React from 'react';
import { Button, Table, Tabs, notification } from 'antd';
import React, { useEffect, useState } from 'react';
import './index.less';
@ -12,22 +12,39 @@ import { toChainSymbol } from '../../contexts/chainPair';
import {
formatUSD,
shortenAddress,
EtherscanLink,
ExplorerLink,
Identicon,
programIds,
} from '@oyster/common';
import { useWormholeTransactions } from '../../hooks/useWormholeTransactions';
import { ASSET_CHAIN } from '../../utils/assets';
import { TokenChain } from '../TokenDisplay/tokenChain';
import bs58 from 'bs58';
import { SyncOutlined } from '@ant-design/icons';
import { typeToIcon } from '../Transfer';
import { ProgressUpdate } from '../../models/bridge';
import { WormholeFactory } from '../../contracts/WormholeFactory';
import { useEthereum } from '../../contexts';
import { useBridge } from '../../contexts/bridge';
TimeAgo.addDefaultLocale(en);
const timeAgo = new TimeAgo('en-US');
export const RecentTransactionsTable = () => {
const { loading: loadingTransfers, transfers } = useWormholeTransactions();
const { TabPane } = Tabs;
const columns = [
export const RecentTransactionsTable = (props: {
showUserTransactions?: boolean;
}) => {
const {
loading: loadingTransfers,
transfers,
userTransfers,
} = useWormholeTransactions();
const { provider } = useEthereum();
const bridge = useBridge();
const [completedVAAs, setCompletedVAAs] = useState<Array<string>>([]);
const baseColumns = [
{
title: '',
dataIndex: 'logo',
@ -68,31 +85,29 @@ export const RecentTransactionsTable = () => {
dataIndex: 'symbol',
key: 'symbol',
render(text: string, record: any) {
const urlText = record.symbol || record.address;
return {
props: { style: {} },
children: record.symbol ? (
<Link
to={`/move?from=${toChainSymbol(record.chain)}&token=${
record.symbol
}`}
>
<span style={{ display: 'inline-flex', alignItems: 'center' }}>
{record.symbol}
</span>
</Link>
) : record.lockup.assetChain === ASSET_CHAIN.Solana ? (
<ExplorerLink
address={record.address}
length={5}
type={'address'}
/>
) : (
<EtherscanLink
address={record.address}
type={'address'}
length={5}
/>
),
children:
record.lockup.assetChain === ASSET_CHAIN.Solana ? (
<a
href={`https://explorer.solana.com/address/${record.address}`}
// eslint-disable-next-line react/jsx-no-target-blank
target="_blank"
title={urlText}
>
{record.symbol || shortenAddress(urlText, 5)}
</a>
) : (
<a
href={`https://etherscan.io/address/${record.address}`}
// eslint-disable-next-line react/jsx-no-target-blank
target="_blank"
title={urlText}
>
{record.symbol || shortenAddress(urlText, 5)}
</a>
),
};
},
},
@ -138,6 +153,9 @@ export const RecentTransactionsTable = () => {
};
},
},
];
const columns = [
...baseColumns,
{
title: 'Status',
dataIndex: 'status',
@ -154,20 +172,203 @@ export const RecentTransactionsTable = () => {
},
},
];
const userColumns = [
...baseColumns,
{
title: 'Status',
dataIndex: 'status',
key: 'status',
render(text: string, record: any) {
const status =
completedVAAs.indexOf(record.txhash) > 0
? 'Completed'
: record.status;
return {
props: { style: {} },
children: (
<>
<span className={`${record.status?.toLowerCase()}`}>
{status}
</span>
{status === 'Failed' ? (
<Button
onClick={() => {
const NotificationContent = () => {
const [activeSteps, setActiveSteps] = useState<
ProgressUpdate[]
>([]);
let counter = 0;
useEffect(() => {
(async () => {
const signer = provider?.getSigner();
if (!signer || !bridge) {
setActiveSteps([
...activeSteps,
{
message: 'Connect your Ethereum Wallet',
type: 'error',
group: 'error',
step: counter++,
},
]);
} else {
const lockup = record.lockup;
let vaa = lockup.vaa;
for (let i = vaa.length; i > 0; i--) {
if (vaa[i] == 0xff) {
vaa = vaa.slice(0, i);
break;
}
}
let signatures = await bridge.fetchSignatureStatus(
lockup.signatureAccount,
);
let sigData = Buffer.of(
...signatures.reduce(
(previousValue, currentValue) => {
previousValue.push(currentValue.index);
previousValue.push(...currentValue.signature);
return previousValue;
},
new Array<number>(),
),
);
vaa = Buffer.concat([
vaa.slice(0, 5),
Buffer.of(signatures.length),
sigData,
vaa.slice(6),
]);
let wh = WormholeFactory.connect(
programIds().wormhole.bridge,
signer,
);
let group = 'Finalizing transfer';
setActiveSteps([
...activeSteps,
{
message: 'Sign the claim...',
type: 'wait',
group,
step: counter++,
},
]);
let tx = await wh.submitVAA(vaa);
setActiveSteps([
...activeSteps,
{
message:
'Waiting for tokens unlock to be mined...',
type: 'wait',
group,
step: counter++,
},
]);
await tx.wait(1);
setActiveSteps([
...activeSteps,
{
message: 'Execution of VAA succeeded',
type: 'done',
group,
step: counter++,
},
]);
}
})();
}, [setActiveSteps]);
return (
<div>
<div
style={{
textAlign: 'left',
display: 'flex',
flexDirection: 'column',
}}
>
{(() => {
let group = '';
return activeSteps.map((step, i) => {
let prevGroup = group;
group = step.group;
let newGroup = prevGroup !== group;
return (
<>
{newGroup && <span>{group}</span>}
<span style={{ marginLeft: 15 }}>
{typeToIcon(
step.type,
activeSteps.length - 1 === i,
)}{' '}
{step.message}
</span>
</>
);
});
})()}
</div>
</div>
);
};
notification.open({
message: '',
duration: 0,
placement: 'bottomLeft',
description: <NotificationContent />,
className: 'custom-class',
style: {
width: 500,
},
});
}}
shape="circle"
size="large"
type="text"
style={{ color: '#547595', fontSize: '18px' }}
title={'Retry Transaction'}
icon={<SyncOutlined />}
/>
) : null}
</>
),
};
},
},
];
return (
<div id={'recent-tx-container'}>
<div className={'home-subtitle'} style={{ marginBottom: '70px' }}>
Recent Transactions
Transactions
</div>
<Table
scroll={{
scrollToFirstRowOnChange: false,
x: 900,
}}
dataSource={transfers.sort((a, b) => b.date - a.date)}
columns={columns}
loading={loadingTransfers}
/>
<Tabs defaultActiveKey="1" centered>
<TabPane tab="Recent Transactions" key="1">
<Table
scroll={{
scrollToFirstRowOnChange: false,
x: 900,
}}
dataSource={transfers.sort((a, b) => b.date - a.date)}
columns={columns}
loading={loadingTransfers}
/>
</TabPane>
<TabPane tab="My Transactions" key="2">
<Table
scroll={{
scrollToFirstRowOnChange: false,
x: 900,
}}
dataSource={userTransfers.sort((a, b) => b.date - a.date)}
columns={userColumns}
loading={loadingTransfers}
/>
</TabPane>
</Tabs>
</div>
);
};

View File

@ -18,6 +18,7 @@ import { useTokenChainPairState } from '../../contexts/chainPair';
import { LABELS } from '../../constants';
import { useCorrectNetwork } from '../../hooks/useCorrectNetwork';
import { RecentTransactionsTable } from '../RecentTransactionsTable';
import { useBridge } from '../../contexts/bridge';
const { useConnection } = contexts.Connection;
const { useWallet } = contexts.Wallet;
@ -40,6 +41,7 @@ export const typeToIcon = (type: string, isLast: boolean) => {
export const Transfer = () => {
const connection = useConnection();
const bridge = useBridge();
const { wallet, connected } = useWallet();
const { provider, tokenMap } = useEthereum();
const hasCorrespondingNetworks = useCorrectNetwork();
@ -50,6 +52,7 @@ export const Transfer = () => {
setMintAddress,
setLastTypedAccount,
} = useTokenChainPairState();
const [request, setRequest] = useState<TransferRequest>({
from: ASSET_CHAIN.Ethereum,
to: ASSET_CHAIN.Solana,
@ -77,7 +80,7 @@ export const Transfer = () => {
to: B.chain,
info: A.info,
});
}, [A, B, mintAddress]);
}, [A, B, mintAddress, A.info]);
return (
<>
@ -92,7 +95,9 @@ export const Transfer = () => {
onChain={(chain: ASSET_CHAIN) => {
const from = A.chain;
A.setChain(chain);
B.setChain(from);
if (B.chain === chain) {
B.setChain(from);
}
}}
onInputChange={amount => {
setLastTypedAccount(A.chain);
@ -126,7 +131,9 @@ export const Transfer = () => {
onChain={(chain: ASSET_CHAIN) => {
const to = B.chain;
B.setChain(chain);
A.setChain(to);
if (A.chain === chain) {
A.setChain(to);
}
}}
onInputChange={amount => {
setLastTypedAccount(B.chain);
@ -171,6 +178,7 @@ export const Transfer = () => {
setActiveSteps(steps);
},
bridge,
);
}

View File

@ -24,6 +24,9 @@ import {
TransferRequestInfo,
wrappedAssetMintKey,
} from '../models/bridge';
import { useBridge } from './bridge';
import { PublicKey } from '@solana/web3.js';
export interface TokenChainContextState {
info?: TransferRequestInfo;
@ -91,11 +94,22 @@ export const useCurrencyLeg = (mintAddress: string) => {
const [chain, setChain] = useState(ASSET_CHAIN.Ethereum);
const [info, setInfo] = useState<TransferRequestInfo>();
const { userAccounts } = useUserAccounts();
const bridge = useBridge();
const { provider, tokens: ethTokens } = useEthereum();
const { tokens: solTokens } = useConnectionConfig();
const connection = useConnection();
const defaultCoinInfo = {
address: '',
name: '',
balance: new BigNumber(0),
decimals: 0,
allowance: new BigNumber(0),
isWrapped: false,
chainID: 0,
assetAddress: new Buffer(0),
mint: '',
};
useEffect(() => {
if (!provider || !connection) {
return;
@ -111,23 +125,44 @@ export const useCurrencyLeg = (mintAddress: string) => {
// sol asset on sol chain
//let ethAddress: string = '';
if (solToken) {
// let signer = provider.getSigner();
// let e = WrappedAssetFactory.connect(asset, provider);
// let addr = await signer.getAddress();
// let decimals = await e.decimals();
// let symbol = await e.symbol();
// console.log({ chain, solToken, ethToken });
if (chain === ASSET_CHAIN.Solana) {
if (!solToken) {
setInfo(defaultCoinInfo);
return;
}
// TODO: checked if mint is wrapped mint from eth...
const currentAccount = userAccounts?.find(
a => a.info.mint.toBase58() === solToken.address,
);
const assetMeta = await bridge?.fetchAssetMeta(
new PublicKey(solToken.address),
);
const accounts = userAccounts
.filter(a => a.info.mint.toBase58() === solToken.address)
.sort((a, b) => a.info.amount.toNumber() - b.info.amount.toNumber());
if (!assetMeta || !currentAccount) {
setInfo(defaultCoinInfo);
return;
}
console.log(accounts);
let info = {
address: currentAccount.pubkey.toBase58(),
name: solToken.symbol,
balance: new BigNumber(currentAccount?.info.amount.toNumber() || 0),
allowance: new BigNumber(0),
decimals: solToken.decimals,
isWrapped: assetMeta.chain != ASSET_CHAIN.Solana,
chainID: assetMeta.chain,
assetAddress: assetMeta.address,
mint: solToken.address,
};
setInfo(info);
}
if (ethToken) {
if (chain === ASSET_CHAIN.Ethereum) {
if (!ethToken) {
setInfo(defaultCoinInfo);
return;
}
let signer = provider.getSigner();
let e = WrappedAssetFactory.connect(mintAddress, provider);
let addr = await signer.getAddress();
@ -170,12 +205,9 @@ export const useCurrencyLeg = (mintAddress: string) => {
address: info.assetAddress,
chain: info.chainID,
});
console.log(mint.toBase58());
}
console.log(info);
// console.log({ info });
setInfo(info);
}
})();
@ -190,16 +222,13 @@ export const useCurrencyLeg = (mintAddress: string) => {
userAccounts,
]);
return useMemo(
() => ({
amount: amount,
setAmount: setAmount,
chain: chain,
setChain: setChain,
info,
}),
[amount, setAmount, chain, setChain],
);
return {
amount: amount,
setAmount: setAmount,
chain: chain,
setChain: setChain,
info,
};
};
export function TokenChainPairProvider({ children = null as any }) {

View File

@ -5,6 +5,7 @@ import assert from 'assert';
// @ts-ignore
import * as BufferLayout from 'buffer-layout';
import * as bs58 from 'bs58';
import { AssetMeta } from '../models/bridge';
export interface Lockup {
lockupAddress: PublicKey;
@ -71,7 +72,40 @@ class SolanaBridge {
data,
});
}
// fetchAssetMeta fetches the AssetMeta for an SPL token
async fetchAssetMeta(mint: PublicKey): Promise<AssetMeta> {
// @ts-ignore
let configKey = await this.getConfigKey();
let seeds: Array<Buffer> = [
Buffer.from('meta'),
configKey.toBuffer(),
mint.toBuffer(),
];
// @ts-ignore
let metaKey = (
await solanaWeb3.PublicKey.findProgramAddress(seeds, this.programID)
)[0];
let metaInfo = await this.connection.getAccountInfo(metaKey);
if (metaInfo == null || metaInfo.lamports == 0) {
return {
address: mint.toBuffer(),
chain: CHAIN_ID_SOLANA,
decimals: 0,
};
} else {
const dataLayout = BufferLayout.struct([
BufferLayout.u8('assetChain'),
BufferLayout.blob(32, 'assetAddress'),
]);
let wrappedMeta = dataLayout.decode(metaInfo?.data);
return {
address: wrappedMeta.assetAddress,
chain: wrappedMeta.assetChain,
decimals: 0,
};
}
}
// fetchSignatureStatus fetches the signatures for a VAA
async fetchSignatureStatus(signatureStatus: PublicKey): Promise<Signature[]> {
let signatureInfo = await this.connection.getAccountInfo(

View File

@ -4,13 +4,17 @@ import {
useConnectionConfig,
programIds,
notify,
useWallet,
} from '@oyster/common';
import { WORMHOLE_PROGRAM_ID, POSTVAA_INSTRUCTION } from '../utils/ids';
import {
WORMHOLE_PROGRAM_ID,
POSTVAA_INSTRUCTION,
TRANSFER_ASSETS_OUT_INSTRUCTION,
} from '../utils/ids';
import { ASSET_CHAIN } from '../utils/assets';
import { useEthereum } from '../contexts';
import {
Connection,
ParsedInstruction,
PartiallyDecodedInstruction,
PublicKey,
} from '@solana/web3.js';
@ -31,11 +35,6 @@ import { ethers } from 'ethers';
import { useBridge } from '../contexts/bridge';
import { SolanaBridge } from '../core';
interface ParsedData {
info: any;
type: string;
}
type WrappedTransferMeta = {
chain: number;
decimals: number;
@ -53,6 +52,7 @@ type WrappedTransferMeta = {
txhash?: string;
date: number; // timestamp
status?: string;
owner?: string;
lockup?: any;
vaa?: any;
};
@ -105,7 +105,9 @@ const queryWrappedMetaTransactions = async (
const dec = new BN(10).pow(new BN(metaTransfer.assetDecimals));
const rawAmount = new BN(metaTransfer.amount, 2, 'le');
const amount = rawAmount.div(dec).toNumber();
const div = rawAmount.div(dec).toNumber();
const mod = rawAmount.mod(dec).toNumber();
const amount = parseFloat(div + '.' + mod.toString());
const txhash = acc.publicKey.toBase58();
transfers.set(assetAddress, {
@ -142,6 +144,14 @@ const queryWrappedMetaTransactions = async (
if (filteredInstructions && filteredInstructions?.length > 0) {
for (const ins of filteredInstructions) {
const data = bs58.decode((ins as PartiallyDecodedInstruction).data);
if (data[0] === TRANSFER_ASSETS_OUT_INSTRUCTION) {
try {
transfer.owner = (ins as PartiallyDecodedInstruction).accounts[10].toBase58();
} catch {
// Catch no owner
transfer.owner = '';
}
}
if (
data[0] === POSTVAA_INSTRUCTION &&
@ -207,10 +217,12 @@ export const useWormholeTransactions = () => {
const { tokenMap: ethTokens } = useEthereum();
const { tokenMap } = useConnectionConfig();
const { coinList } = useCoingecko();
const { wallet, connected: walletConnected } = useWallet();
const bridge = useBridge();
const [loading, setLoading] = useState<boolean>(true);
const [transfers, setTransfers] = useState<WrappedTransferMeta[]>([]);
const [userTransfers, setUserTransfers] = useState<WrappedTransferMeta[]>([]);
const [amountInUSD, setAmountInUSD] = useState<number>(0);
useEffect(() => {
@ -241,6 +253,16 @@ export const useWormholeTransactions = () => {
})();
}, [connection, setTransfers]);
useEffect(() => {
if (transfers && walletConnected && wallet?.publicKey) {
setUserTransfers(
transfers.filter(t => {
return t.owner === wallet?.publicKey?.toBase58();
}),
);
}
}, [wallet, walletConnected, transfers]);
const coingeckoTimer = useRef<number>(0);
const dataSourcePriceQuery = useCallback(async () => {
if (transfers.length === 0) return;
@ -306,6 +328,7 @@ export const useWormholeTransactions = () => {
return {
loading,
transfers,
userTransfers,
totalInUSD: amountInUSD,
};
};

View File

@ -9,6 +9,7 @@ import { ProgressUpdate, TransferRequest } from './interface';
import BN from 'bn.js';
import { createLockAssetInstruction } from '../lock';
import { TransferOutProposalLayout } from '../transferOutProposal';
import { SolanaBridge } from '../../../core';
export const fromSolana = async (
connection: Connection,
@ -16,17 +17,17 @@ export const fromSolana = async (
request: TransferRequest,
provider: ethers.providers.Web3Provider,
setProgress: (update: ProgressUpdate) => void,
bridge?: SolanaBridge,
) => {
if (
!request.asset ||
!request.amount ||
!request.recipient ||
!request.to ||
!request.info
!request.info ||
!bridge
) {
return;
}
const walletName = 'MetaMask';
const signer = provider?.getSigner();
request.recipient = Buffer.from((await signer.getAddress()).slice(2), 'hex');
const nonce = await provider.getTransactionCount(
@ -34,11 +35,6 @@ export const fromSolana = async (
'pending',
);
const amountBN = ethers.utils.parseUnits(
request.amount.toString(),
request.info.decimals,
);
let counter = 0;
// check difference between lock/approve (invoke lock if allowance < amount)
const steps = {
@ -66,7 +62,7 @@ export const fromSolana = async (
return;
}
let group = 'Lock assets';
let group = 'Initiate transfer';
const programs = programIds();
const bridgeId = programs.wormhole.pubkey;
const authorityKey = await bridgeAuthorityKey(bridgeId);
@ -79,7 +75,7 @@ export const fromSolana = async (
wallet.publicKey,
new PublicKey(request.info.address),
new PublicKey(request.info.mint),
new BN(request.amount.toString()),
new BN(amount),
request.to,
request.recipient,
{
@ -100,6 +96,12 @@ export const fromSolana = async (
amount,
);
setProgress({
message: 'Waiting for Solana approval...',
type: 'user',
group,
step: counter++,
});
let fee_ix = SystemProgram.transfer({
fromPubkey: wallet.publicKey,
toPubkey: authorityKey,
@ -126,29 +128,28 @@ export const fromSolana = async (
let startSlot = slot;
let group = 'Lock assets';
const solConfirmationMessage = (current: number) =>
`Awaiting ETH confirmations: ${current} out of 32`;
let slotUpdateListener = connection.onSlotChange(slot => {
if (completed) return;
const passedSlots = slot.slot - startSlot;
const isLast = passedSlots - 1 === 31;
if (passedSlots < 32) {
// setLoading({
// loading: true,
// message: "Awaiting confirmations",
// progress: {
// completion: (slot.slot - startSlot) / 32 * 100,
// content: `${slot.slot - startSlot}/${32}`
// }
// })
// setProgress({
// message: ethConfirmationMessage(passedBlocks),
// type: isLast ? 'done' : 'wait',
// step: counter++,
// group,
// replace: passedBlocks > 0,
// });
} else {
//setLoading({loading: true, message: "Awaiting guardian confirmation"})
setProgress({
message: solConfirmationMessage(passedSlots),
type: isLast ? 'done' : 'wait',
step: counter++,
group,
replace: passedSlots > 0,
});
if (isLast) {
setProgress({
message: 'Awaiting guardian confirmation',
type: 'wait',
step: counter++,
group,
});
}
}
});
@ -176,27 +177,27 @@ export const fromSolana = async (
connection.removeAccountChangeListener(accountChangeListener);
connection.removeSlotChangeListener(slotUpdateListener);
// let signatures = await bridge.fetchSignatureStatus(
// lockup.signatureAccount,
// );
// let sigData = Buffer.of(
// ...signatures.reduce((previousValue, currentValue) => {
// previousValue.push(currentValue.index);
// previousValue.push(...currentValue.signature);
let signatures = await bridge.fetchSignatureStatus(
lockup.signatureAccount,
);
let sigData = Buffer.of(
...signatures.reduce((previousValue, currentValue) => {
previousValue.push(currentValue.index);
previousValue.push(...currentValue.signature);
// return previousValue;
// }, new Array<number>()),
// );
return previousValue;
}, new Array<number>()),
);
vaa = Buffer.concat([
vaa.slice(0, 5),
Buffer.of(signatures.length),
sigData,
vaa.slice(6),
]);
// vaa = Buffer.concat([
// vaa.slice(0, 5),
// Buffer.of(signatures.length),
// sigData,
// vaa.slice(6),
// ]);
// transferVAA = vaa
try {
await steps.postVAA(request);
await steps.postVAA(request, vaa);
resolve();
} catch {
reject();
@ -206,22 +207,30 @@ export const fromSolana = async (
);
});
},
postVAA: async (request: TransferRequest) => {
postVAA: async (request: TransferRequest, vaa: any) => {
let wh = WormholeFactory.connect(programIds().wormhole.bridge, signer);
// setLoading({
// ...loading,
// loading: true,
// message: "Sign the claim...",
// })
// let tx = await wh.submitVAA(vaa);
// setLoading({
// ...loading,
// loading: true,
// message: "Waiting for tokens unlock to be mined...",
// })
// await tx.wait(1);
// message.success({content: "Execution of VAA succeeded", key: "eth_tx"})
let group = 'Finalizing transfer';
setProgress({
message: 'Sign the claim...',
type: 'wait',
group,
step: counter++,
});
let tx = await wh.submitVAA(vaa);
setProgress({
message: 'Waiting for tokens unlock to be mined...',
type: 'wait',
group,
step: counter++,
});
await tx.wait(1);
setProgress({
message: 'Execution of VAA succeeded',
type: 'done',
group,
step: counter++,
});
//message.success({content: "", key: "eth_tx"})
},
};

View File

@ -37,12 +37,10 @@ export interface TransferRequest {
export const displayBalance = (info?: TransferRequestInfo) => {
try {
return (
new BN(info?.balance?.toString() || 0)
.div(new BN(10).pow(new BN(Math.min((info?.decimals || 0) - 2, 0))))
.toNumber() / 100
);
} catch {
const balance = info?.balance || new BigNumber(0);
const precision = new BigNumber(10).pow(info?.decimals || new BigNumber(0));
return balance.div(precision).toNumber();
} catch (e) {
return 0;
}
};

View File

@ -4,11 +4,12 @@ export const WORMHOLE_PROGRAM_ID = new PublicKey(
'WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC',
);
export const TRANSFER_ASSETS_OUT_INSTRUCTION: number = 1;
export const POSTVAA_INSTRUCTION: number = 2;
const INSTRUCTION_LOOKUP: { [key: number]: string } = {
0: 'Initialize Bridge',
1: 'Transfer Assets Out',
[TRANSFER_ASSETS_OUT_INSTRUCTION]: 'Transfer Assets Out',
[POSTVAA_INSTRUCTION]: 'Post VAA',
3: 'Evict Transfer Proposal',
4: 'Evict Claimed VAA',