mirror of https://github.com/certusone/oyster.git
only show and fetch own transactions (#107)
* fixed button with no provider * feat: fix bridge transactions * fix: connection selection * only show and fetch own transactions * Added better messages * added memo to columns Co-authored-by: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com>
This commit is contained in:
parent
ea2af3b06f
commit
18bda5527f
|
@ -1,4 +1,4 @@
|
|||
import { programIds, sendTransactionWithRetry } from '@oyster/common';
|
||||
import { programIds, sendTransactionWithRetry, sleep } from '@oyster/common';
|
||||
import { WalletAdapter } from '@solana/wallet-base';
|
||||
import { ethers } from 'ethers';
|
||||
import { WormholeFactory } from '../../contracts/WormholeFactory';
|
||||
|
@ -113,6 +113,17 @@ export const fromSolana = async (
|
|||
wallet,
|
||||
[ix, fee_ix, lock_ix],
|
||||
[],
|
||||
undefined,
|
||||
false,
|
||||
undefined,
|
||||
() => {
|
||||
setProgress({
|
||||
message: 'Executing Solana Transaction',
|
||||
type: 'wait',
|
||||
group,
|
||||
step: counter++,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return steps.wait(request, transferKey, slot);
|
||||
|
@ -124,31 +135,39 @@ export const fromSolana = async (
|
|||
) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let completed = false;
|
||||
let unsubscribed = false;
|
||||
let startSlot = slot;
|
||||
|
||||
let group = 'Lock assets';
|
||||
const solConfirmationMessage = (current: number) =>
|
||||
`Awaiting ETH confirmations: ${current} out of 32`;
|
||||
`Awaiting Solana confirmations: ${current} out of 32`;
|
||||
let replaceMessage = false;
|
||||
let slotUpdateListener = connection.onSlotChange(slot => {
|
||||
if (completed) return;
|
||||
const passedSlots = slot.slot - startSlot;
|
||||
if (unsubscribed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const passedSlots = Math.min(Math.max(slot.slot - startSlot, 0), 32);
|
||||
const isLast = passedSlots - 1 === 31;
|
||||
if (passedSlots < 32) {
|
||||
if (passedSlots <= 32) {
|
||||
setProgress({
|
||||
message: solConfirmationMessage(passedSlots),
|
||||
type: isLast ? 'done' : 'wait',
|
||||
step: counter++,
|
||||
group,
|
||||
replace: passedSlots > 0,
|
||||
replace: replaceMessage,
|
||||
});
|
||||
replaceMessage = true;
|
||||
}
|
||||
|
||||
if (completed || isLast) {
|
||||
unsubscribed = true;
|
||||
setProgress({
|
||||
message: 'Awaiting guardian confirmation. (Up to few min.)',
|
||||
type: 'wait',
|
||||
step: counter++,
|
||||
group,
|
||||
});
|
||||
if (isLast) {
|
||||
setProgress({
|
||||
message: 'Awaiting guardian confirmation',
|
||||
type: 'wait',
|
||||
step: counter++,
|
||||
group,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -175,10 +194,19 @@ export const fromSolana = async (
|
|||
completed = true;
|
||||
connection.removeAccountChangeListener(accountChangeListener);
|
||||
connection.removeSlotChangeListener(slotUpdateListener);
|
||||
let signatures;
|
||||
|
||||
while (!signatures) {
|
||||
try {
|
||||
signatures = await bridge.fetchSignatureStatus(
|
||||
lockup.signatureAccount,
|
||||
);
|
||||
break;
|
||||
} catch {
|
||||
await sleep(500);
|
||||
}
|
||||
}
|
||||
|
||||
let signatures = await bridge.fetchSignatureStatus(
|
||||
lockup.signatureAccount,
|
||||
);
|
||||
let sigData = Buffer.of(
|
||||
...signatures.reduce((previousValue, currentValue) => {
|
||||
previousValue.push(currentValue.index);
|
||||
|
@ -217,7 +245,7 @@ export const fromSolana = async (
|
|||
});
|
||||
let tx = await wh.submitVAA(vaa);
|
||||
setProgress({
|
||||
message: 'Waiting for tokens unlock to be mined...',
|
||||
message: 'Waiting for tokens unlock to be mined... (Up to few min.)',
|
||||
type: 'wait',
|
||||
group,
|
||||
step: counter++,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { BigNumber } from 'bignumber.js';
|
||||
import {ethers} from "ethers";
|
||||
import { ethers } from 'ethers';
|
||||
import { ASSET_CHAIN } from '../constants';
|
||||
|
||||
export interface ProgressUpdate {
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
import { AccountInfo } from '@solana/spl-token';
|
||||
import { TransferRequest, ProgressUpdate } from './interface';
|
||||
import { WalletAdapter } from '@solana/wallet-base';
|
||||
import { BigNumber } from "bignumber.js";
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
|
||||
export const toSolana = async (
|
||||
connection: Connection,
|
||||
|
@ -180,7 +180,7 @@ export const toSolana = async (
|
|||
});
|
||||
let res = await e.approve(programIds().wormhole.bridge, amountBN);
|
||||
setProgress({
|
||||
message: 'Waiting for ETH transaction to be mined...',
|
||||
message: 'Waiting for ETH transaction to be mined... (Up to few min.)',
|
||||
type: 'wait',
|
||||
group,
|
||||
step: counter++,
|
||||
|
@ -243,7 +243,7 @@ export const toSolana = async (
|
|||
false,
|
||||
);
|
||||
setProgress({
|
||||
message: 'Waiting for ETH transaction to be mined...',
|
||||
message: 'Waiting for ETH transaction to be mined... (Up to few min.)',
|
||||
type: 'wait',
|
||||
group,
|
||||
step: counter++,
|
||||
|
|
|
@ -7,6 +7,16 @@ import * as BufferLayout from 'buffer-layout';
|
|||
import * as bs58 from 'bs58';
|
||||
import { AssetMeta } from '../bridge';
|
||||
|
||||
export enum LockupStatus {
|
||||
AWAITING_VAA,
|
||||
UNCLAIMED_VAA,
|
||||
COMPLETED,
|
||||
}
|
||||
|
||||
export interface LockupWithStatus extends Lockup {
|
||||
status: LockupStatus;
|
||||
}
|
||||
|
||||
export interface Lockup {
|
||||
lockupAddress: PublicKey;
|
||||
amount: BN;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Button, Table, Tabs, notification } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import './index.less';
|
||||
|
||||
|
@ -34,11 +34,7 @@ const { TabPane } = Tabs;
|
|||
export const RecentTransactionsTable = (props: {
|
||||
showUserTransactions?: boolean;
|
||||
}) => {
|
||||
const {
|
||||
loading: loadingTransfers,
|
||||
transfers,
|
||||
userTransfers,
|
||||
} = useWormholeTransactions();
|
||||
const { loading: loadingTransfers, transfers } = useWormholeTransactions();
|
||||
const { provider } = useEthereum();
|
||||
const bridge = useBridge();
|
||||
|
||||
|
@ -154,221 +150,197 @@ export const RecentTransactionsTable = (props: {
|
|||
},
|
||||
},
|
||||
];
|
||||
const columns = [
|
||||
...baseColumns,
|
||||
{
|
||||
title: 'Status',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
render(text: string, record: any) {
|
||||
return {
|
||||
props: { style: {} },
|
||||
children: (
|
||||
<span className={`${record.status?.toLowerCase()}`}>
|
||||
{record.status}
|
||||
</span>
|
||||
),
|
||||
};
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
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;
|
||||
const userColumns = useMemo(
|
||||
() => [
|
||||
...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++,
|
||||
},
|
||||
new Array<number>(),
|
||||
),
|
||||
);
|
||||
]);
|
||||
} 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,
|
||||
);
|
||||
|
||||
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 previousValue;
|
||||
},
|
||||
new Array<number>(),
|
||||
),
|
||||
);
|
||||
|
||||
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>
|
||||
</>
|
||||
);
|
||||
});
|
||||
})()}
|
||||
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... (Up to few min.)',
|
||||
type: 'wait',
|
||||
group,
|
||||
step: counter++,
|
||||
},
|
||||
]);
|
||||
await tx.wait(1);
|
||||
setActiveSteps([
|
||||
...activeSteps,
|
||||
{
|
||||
message: 'Execution of VAA succeeded',
|
||||
type: 'done',
|
||||
group,
|
||||
step: counter++,
|
||||
},
|
||||
]);
|
||||
setCompletedVAAs([
|
||||
...completedVAAs,
|
||||
record.txhash,
|
||||
]);
|
||||
}
|
||||
})();
|
||||
}, [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>
|
||||
</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}
|
||||
</>
|
||||
),
|
||||
};
|
||||
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}
|
||||
</>
|
||||
),
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
],
|
||||
[completedVAAs, bridge, provider],
|
||||
);
|
||||
return (
|
||||
<div id={'recent-tx-container'}>
|
||||
<div className={'home-subtitle'} style={{ marginBottom: '70px' }}>
|
||||
Transactions
|
||||
My Recent Transactions
|
||||
</div>
|
||||
<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>
|
||||
<Table
|
||||
scroll={{
|
||||
scrollToFirstRowOnChange: false,
|
||||
x: 900,
|
||||
}}
|
||||
dataSource={transfers.sort((a, b) => b.date - a.date)}
|
||||
columns={userColumns}
|
||||
loading={loadingTransfers}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ export const useCorrectNetwork = () => {
|
|||
if (chainId === 5) {
|
||||
setHasCorrespondingNetworks(env === 'testnet');
|
||||
} else if (chainId === 1) {
|
||||
setHasCorrespondingNetworks(env === 'mainnet-beta');
|
||||
setHasCorrespondingNetworks(env.includes('mainnet-beta'));
|
||||
} else {
|
||||
setHasCorrespondingNetworks(false);
|
||||
}
|
||||
|
|
|
@ -1,27 +1,33 @@
|
|||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
notify,
|
||||
programIds,
|
||||
useConnection,
|
||||
useConnectionConfig,
|
||||
programIds,
|
||||
notify,
|
||||
useWallet,
|
||||
ParsedAccountBase,
|
||||
} from '@oyster/common';
|
||||
import {
|
||||
WORMHOLE_PROGRAM_ID,
|
||||
POSTVAA_INSTRUCTION,
|
||||
TRANSFER_ASSETS_OUT_INSTRUCTION,
|
||||
WORMHOLE_PROGRAM_ID,
|
||||
} from '../utils/ids';
|
||||
import { ASSET_CHAIN } from '../utils/assets';
|
||||
import { useEthereum } from '../contexts';
|
||||
import {
|
||||
AccountInfo,
|
||||
Connection,
|
||||
ParsedAccountData,
|
||||
PartiallyDecodedInstruction,
|
||||
PublicKey,
|
||||
RpcResponseAndContext,
|
||||
} from '@solana/web3.js';
|
||||
import {
|
||||
bridgeAuthorityKey,
|
||||
LockupStatus,
|
||||
LockupWithStatus,
|
||||
SolanaBridge,
|
||||
TransferOutProposalLayout,
|
||||
WormholeFactory,
|
||||
} from '@solana/bridge-sdk';
|
||||
|
||||
import bs58 from 'bs58';
|
||||
|
@ -31,11 +37,10 @@ import {
|
|||
useCoingecko,
|
||||
} from '../contexts/coingecko';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import { WormholeFactory } from '@solana/bridge-sdk';
|
||||
import { ethers } from 'ethers';
|
||||
import { useBridge } from '../contexts/bridge';
|
||||
import { SolanaBridge } from '@solana/bridge-sdk';
|
||||
import BN from 'bn.js';
|
||||
import { keccak256 } from 'ethers/utils';
|
||||
|
||||
type WrappedTransferMeta = {
|
||||
chain: number;
|
||||
|
@ -59,6 +64,86 @@ type WrappedTransferMeta = {
|
|||
|
||||
const transferCache = new Map<string, WrappedTransferMeta>();
|
||||
|
||||
const queryOwnWrappedMetaTransactions = async (
|
||||
authorityKey: PublicKey,
|
||||
connection: Connection,
|
||||
setTransfers: (arr: WrappedTransferMeta[]) => void,
|
||||
provider: ethers.providers.Web3Provider,
|
||||
bridge?: SolanaBridge,
|
||||
owner?: PublicKey | null,
|
||||
) => {
|
||||
if (owner && bridge) {
|
||||
const transfers = new Map<string, WrappedTransferMeta>();
|
||||
let wh = WormholeFactory.connect(programIds().wormhole.bridge, provider);
|
||||
const res: RpcResponseAndContext<
|
||||
Array<{ pubkey: PublicKey; account: AccountInfo<ParsedAccountData> }>
|
||||
> = await connection.getParsedTokenAccountsByOwner(
|
||||
owner,
|
||||
{ programId: programIds().token },
|
||||
'single',
|
||||
);
|
||||
let lockups: LockupWithStatus[] = [];
|
||||
for (const acc of res.value) {
|
||||
const accLockups = await bridge.fetchTransferProposals(acc.pubkey);
|
||||
lockups.push(
|
||||
...accLockups.map(v => {
|
||||
return {
|
||||
status: LockupStatus.AWAITING_VAA,
|
||||
...v,
|
||||
};
|
||||
}),
|
||||
);
|
||||
for (let lockup of lockups) {
|
||||
if (lockup.vaaTime === undefined || lockup.vaaTime === 0) continue;
|
||||
|
||||
let signingData = lockup.vaa.slice(lockup.vaa[5] * 66 + 6);
|
||||
for (let i = signingData.length; i > 0; i--) {
|
||||
if (signingData[i] == 0xff) {
|
||||
signingData = signingData.slice(0, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let hash = keccak256(signingData);
|
||||
let submissionStatus = await wh.consumedVAAs(hash);
|
||||
|
||||
lockup.status = submissionStatus
|
||||
? LockupStatus.COMPLETED
|
||||
: LockupStatus.UNCLAIMED_VAA;
|
||||
}
|
||||
}
|
||||
for (const ls of lockups) {
|
||||
const txhash = ls.lockupAddress.toBase58();
|
||||
let assetAddress: string = '';
|
||||
if (ls.assetChain !== ASSET_CHAIN.Solana) {
|
||||
assetAddress = Buffer.from(ls.assetAddress.slice(12)).toString('hex');
|
||||
} else {
|
||||
assetAddress = new PublicKey(ls.assetAddress).toBase58();
|
||||
}
|
||||
const dec = new BigNumber(10).pow(new BigNumber(ls.assetDecimals));
|
||||
const rawAmount = new BigNumber(ls.amount.toString());
|
||||
const amount = rawAmount.div(dec).toNumber();
|
||||
transfers.set(txhash, {
|
||||
publicKey: ls.lockupAddress,
|
||||
amount,
|
||||
date: ls.vaaTime,
|
||||
chain: ls.assetChain,
|
||||
address: assetAddress,
|
||||
decimals: 9,
|
||||
txhash,
|
||||
explorer: `https://explorer.solana.com/address/${txhash}`,
|
||||
lockup: ls,
|
||||
status:
|
||||
ls.status === LockupStatus.UNCLAIMED_VAA
|
||||
? 'Failed'
|
||||
: ls.status === LockupStatus.AWAITING_VAA
|
||||
? 'In Process'
|
||||
: 'Completed',
|
||||
});
|
||||
}
|
||||
setTransfers([...transfers.values()]);
|
||||
}
|
||||
};
|
||||
|
||||
const queryWrappedMetaTransactions = async (
|
||||
authorityKey: PublicKey,
|
||||
connection: Connection,
|
||||
|
@ -238,12 +323,11 @@ export const useWormholeTransactions = () => {
|
|||
const { tokenMap: ethTokens } = useEthereum();
|
||||
const { tokenMap } = useConnectionConfig();
|
||||
const { coinList } = useCoingecko();
|
||||
const { wallet, connected: walletConnected } = useWallet();
|
||||
const { wallet } = 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(() => {
|
||||
|
@ -263,26 +347,17 @@ export const useWormholeTransactions = () => {
|
|||
(window as any).ethereum,
|
||||
);
|
||||
// query wrapped assets that were imported to solana from other chains
|
||||
queryWrappedMetaTransactions(
|
||||
queryOwnWrappedMetaTransactions(
|
||||
authorityKey,
|
||||
connection,
|
||||
setTransfers,
|
||||
provider,
|
||||
bridge,
|
||||
wallet?.publicKey,
|
||||
).then(() => setLoading(false));
|
||||
}
|
||||
})();
|
||||
}, [connection, setTransfers]);
|
||||
|
||||
useEffect(() => {
|
||||
if (transfers && walletConnected && wallet?.publicKey) {
|
||||
setUserTransfers(
|
||||
transfers.filter(t => {
|
||||
return t.owner === wallet?.publicKey?.toBase58();
|
||||
}),
|
||||
);
|
||||
}
|
||||
}, [wallet, walletConnected, transfers]);
|
||||
}, [connection, setTransfers, wallet?.publicKey]);
|
||||
|
||||
const coingeckoTimer = useRef<number>(0);
|
||||
const dataSourcePriceQuery = useCallback(async () => {
|
||||
|
@ -350,7 +425,6 @@ export const useWormholeTransactions = () => {
|
|||
return {
|
||||
loading,
|
||||
transfers,
|
||||
userTransfers,
|
||||
totalInUSD: amountInUSD,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
} from '@solana/spl-token-registry';
|
||||
|
||||
export type ENV =
|
||||
| 'mainnet-beta (Serum)'
|
||||
| 'mainnet-beta'
|
||||
| 'testnet'
|
||||
| 'devnet'
|
||||
|
@ -31,10 +32,15 @@ export type ENV =
|
|||
|
||||
export const ENDPOINTS = [
|
||||
{
|
||||
name: 'mainnet-beta' as ENV,
|
||||
name: 'mainnet-beta (Serum)' as ENV,
|
||||
endpoint: 'https://solana-api.projectserum.com/',
|
||||
ChainId: ChainId.MainnetBeta,
|
||||
},
|
||||
{
|
||||
name: 'mainnet-beta' as ENV,
|
||||
endpoint: 'https://api.mainnet-beta.solana.com',
|
||||
ChainId: ChainId.MainnetBeta,
|
||||
},
|
||||
{
|
||||
name: 'testnet' as ENV,
|
||||
endpoint: clusterApiUrl('testnet'),
|
||||
|
@ -412,6 +418,7 @@ export const sendTransactionWithRetry = async (
|
|||
commitment: Commitment = 'singleGossip',
|
||||
includesFeePayer: boolean = false,
|
||||
block?: BlockhashAndFeeCalculator,
|
||||
beforeSend?: () => void,
|
||||
) => {
|
||||
let transaction = new Transaction();
|
||||
instructions.forEach(instruction => transaction.add(instruction));
|
||||
|
@ -436,6 +443,10 @@ export const sendTransactionWithRetry = async (
|
|||
transaction = await wallet.signTransaction(transaction);
|
||||
}
|
||||
|
||||
if (beforeSend) {
|
||||
beforeSend();
|
||||
}
|
||||
|
||||
const { txid, slot } = await sendSignedTransaction({
|
||||
connection,
|
||||
signedTransaction: transaction,
|
||||
|
@ -521,7 +532,7 @@ export async function sendSignedTransaction({
|
|||
}
|
||||
throw new Error(JSON.stringify(simulateResult.err));
|
||||
}
|
||||
throw new Error('Transaction failed');
|
||||
// throw new Error('Transaction failed');
|
||||
} finally {
|
||||
done = true;
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ export const PROGRAM_IDS = [
|
|||
];
|
||||
|
||||
export const setProgramIds = (envName: string) => {
|
||||
let instance = PROGRAM_IDS.find(env => env.name === envName);
|
||||
let instance = PROGRAM_IDS.find(env => envName.indexOf(env.name) >= 0);
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue