Added list of locked funds accounts in the front page

This commit is contained in:
juan 2021-03-03 15:45:24 -05:00
parent 04012e024f
commit bbedbae8c6
6 changed files with 202 additions and 24 deletions

View File

@ -0,0 +1,95 @@
import {useEffect, useState} from "react";
import {contexts} from "@oyster/common";
import * as BufferLayout from 'buffer-layout'
import {WORMHOLE_PROGRAM_ID} from "../utils/ids";
import BN from "bn.js";
import {getAssetAmountInUSD, getAssetName, getAssetTokenSymbol} from "../utils/assets";
const { useConnection } = contexts.Connection;
interface ParsedData {
amount: number,
rawAmount: string,
parsedAssetAddress: string,
parsedAccount: any,
assetDecimals: number,
tokenName: string,
tokenSymbol: string,
sourceAddress: string,
targetAddress: string,
amountInUSD: number,
}
export const useLockedFundsAccounts = () => {
const connection = useConnection();
const [lockedSolanaAccounts, setLockedSolanaAccounts] = useState<ParsedData[]>([]);
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
const queryTxs = async () => {
setLoading(true);
const programAccounts = await connection.getProgramAccounts(
WORMHOLE_PROGRAM_ID
);
const dataLayout = BufferLayout.struct([
BufferLayout.blob(32, 'amount'),
BufferLayout.u8('toChain'),
BufferLayout.blob(32, 'sourceAddress'),
BufferLayout.blob(32, 'targetAddress'),
BufferLayout.blob(32, 'assetAddress'),
BufferLayout.u8('assetChain'),
BufferLayout.u8('assetDecimals'),
BufferLayout.seq(BufferLayout.u8(), 1), // 4 byte alignment because a u32 is following
BufferLayout.u32('nonce'),
BufferLayout.blob(1001, 'vaa'),
BufferLayout.seq(BufferLayout.u8(), 3), // 4 byte alignment because a u32 is following
BufferLayout.u32('vaaTime'),
BufferLayout.u32('lockupTime'),
BufferLayout.u8('pokeCounter'),
BufferLayout.blob(32, 'signatureAccount'),
BufferLayout.u8('initialized'),
]);
const filteredParsedAccounts: ParsedData[] = [];
programAccounts.map(acc => {
try {
const parsedAccount = dataLayout.decode(acc.account.data)
if ((parsedAccount.assetChain === 1 || parsedAccount.assetChain ===2 ) &&
(parsedAccount.toChain === 1 || parsedAccount.toChain === 2)) {
const dec = new BN(10).pow(new BN(parsedAccount.assetDecimals));
const rawAmount = new BN(parsedAccount.amount, 2, "le")
const amount = rawAmount.div(dec).toNumber();
const parsedAssetAddress: string = new Buffer(parsedAccount.assetAddress.slice(12)).toString("hex")
const parsedData: ParsedData = {
amount: amount,
rawAmount: rawAmount.toString(),
parsedAssetAddress: parsedAssetAddress,
parsedAccount: parsedAccount,
assetDecimals: parsedAccount.assetDecimals,
sourceAddress: new Buffer(parsedAccount.sourceAddress.slice(12)).toString("hex"),
targetAddress: new Buffer(parsedAccount.targetAddress.slice(12)).toString("hex"),
tokenName: getAssetName(parsedAssetAddress, parsedAccount.assetChain),
tokenSymbol: getAssetTokenSymbol(parsedAssetAddress, parsedAccount.assetChain),
amountInUSD: getAssetAmountInUSD(amount, parsedAssetAddress, parsedAccount.assetChain),
};
filteredParsedAccounts.push(parsedData)
}
} catch (error){
return
}
});
return filteredParsedAccounts;
}
Promise.all([queryTxs()]).then((all) => {
setLoading(false);
setLockedSolanaAccounts(all[0])
});
}, []);
return {
loading,
lockedSolanaAccounts,
total: lockedSolanaAccounts.reduce((acc, val) => {
return acc + val.amountInUSD;
}, 0)
};
}

View File

@ -0,0 +1,21 @@
export const getAssetName = (
parsedAssetAddress: string,
assetChain: number,
) => {
return parsedAssetAddress.slice(0, 5);
};
export const getAssetTokenSymbol = (
parsedAssetAddress: string,
assetChain: number,
) => {
return parsedAssetAddress.slice(0, 5);
};
export const getAssetAmountInUSD = (
amount: number,
parsedAssetAddress: string,
assetChain: number,
) => {
return amount;
};

View File

@ -0,0 +1,5 @@
import { PublicKey } from '@solana/web3.js';
export const WORMHOLE_PROGRAM_ID = new PublicKey(
'WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC',
);

View File

@ -1,14 +1,16 @@
import { MintInfo } from '@solana/spl-token';
import { Table, Tag, Space, Card, Col, Row, Statistic, Button } from 'antd';
import React, { useEffect, useState } from 'react';
import React, {useEffect, useMemo, useState} from 'react';
import { GUTTER, LABELS } from '../../constants';
import { contexts, ParsedAccount, utils } from '@oyster/common';
import {contexts, ExplorerLink, ParsedAccount, utils} from '@oyster/common';
import { useMarkets } from '../../contexts/market';
import { LendingReserveItem } from './item';
import './itemStyle.less';
import { Totals } from '../../models/totals';
import { Link } from 'react-router-dom';
import {useLockedFundsAccounts} from "../../hooks/useLockedFundsAccounts";
import {EtherscanLink} from "@oyster/common/dist/lib/components/EtherscanLink";
const { fromLamports, getTokenName, wadToLamports } = utils;
const { cache } = contexts.Accounts;
const { useConnectionConfig } = contexts.Connection;
@ -16,6 +18,7 @@ const { useConnectionConfig } = contexts.Connection;
export const HomeView = () => {
const { marketEmitter, midPriceInUSD } = useMarkets();
const { tokenMap } = useConnectionConfig();
const {loading: loadingLockedAccounts, lockedSolanaAccounts, total: totalLocked } = useLockedFundsAccounts();
const [totals, setTotals] = useState<Totals>({
marketSize: 0,
numberOfAssets: 0,
@ -76,36 +79,50 @@ export const HomeView = () => {
};
}, [marketEmitter, midPriceInUSD, setTotals, tokenMap]);
const dataSource = [
{
key: '1',
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
key: '2',
name: 'John',
age: 42,
address: '10 Downing Street',
},
];
const dataSource = useMemo(() => {
if (loadingLockedAccounts) return [];
console.log(lockedSolanaAccounts)
return lockedSolanaAccounts.map((acc, index) => {
return {
key: index.toString(),
symbol: acc.tokenSymbol,
name: acc.tokenName,
amount: acc.amountInUSD,
sourceAddress: acc.parsedAccount.assetChain === 1 ?
<ExplorerLink address={acc.sourceAddress} type={"address"} /> :
<EtherscanLink address={acc.sourceAddress} type={"address"} />,
targetAddress: acc.parsedAccount.toChain === 1 ?
<ExplorerLink address={acc.targetAddress} type={"address"} /> :
<EtherscanLink address={acc.targetAddress} type={"address"} />,
}
})
}, [loadingLockedAccounts, lockedSolanaAccounts])
const columns = [
{
title: 'Symbol',
dataIndex: 'symbol',
key: 'symbol',
},
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
title: 'Amount',
dataIndex: 'amount',
key: 'amount',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
title: 'Source Address',
dataIndex: 'sourceAddress',
key: 'sourceAddress',
},
{
title: 'Target Address',
dataIndex: 'targetAddress',
key: 'targetAddress',
},
];
@ -127,7 +144,7 @@ export const HomeView = () => {
<Col xs={24} xl={12}>
<Statistic
className="home-statistic"
title="$1,231"
title={`$${totalLocked}`}
value="TOTAL VALUE LOCKED"
/>
</Col>

View File

@ -33,4 +33,5 @@
.home-info-row {
margin-bottom: 10px;
}
min-height: 45vh;
}

View File

@ -0,0 +1,39 @@
import React from 'react';
import { Typography } from 'antd';
import { shortenAddress } from '../../utils/utils';
export const EtherscanLink = (props: {
address: string ;
type: string;
code?: boolean;
style?: React.CSSProperties;
length?: number;
}) => {
const { type, code } = props;
const address = props.address;
if (!address) {
return null;
}
const length = props.length ?? 9;
return (
<a
href={`https://etherscan.io/${type}/${address}`}
// eslint-disable-next-line react/jsx-no-target-blank
target="_blank"
title={address}
style={props.style}
>
{code ? (
<Typography.Text style={props.style} code>
{shortenAddress(address, length)}
</Typography.Text>
) : (
shortenAddress(address, length)
)}
</a>
);
};