mirror of https://github.com/certusone/oyster.git
Added modal to select token chain
This commit is contained in:
parent
979a369f6a
commit
b3a0dabf4b
|
@ -1,12 +1,9 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { NumericInput } from '@oyster/common';
|
import { NumericInput } from '@oyster/common';
|
||||||
import { Card, Select } from 'antd';
|
import { Card } from 'antd';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import { useEthereum } from '../../contexts';
|
|
||||||
import { TokenDisplay } from '../TokenDisplay';
|
|
||||||
import { ASSET_CHAIN } from '../../models/bridge/constants';
|
import { ASSET_CHAIN } from '../../models/bridge/constants';
|
||||||
|
import { TokenSelectModal } from '../TokenSelectModal';
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
export function Input(props: {
|
export function Input(props: {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -18,33 +15,6 @@ export function Input(props: {
|
||||||
onInputChange: (value: number | undefined) => void;
|
onInputChange: (value: number | undefined) => void;
|
||||||
}) {
|
}) {
|
||||||
const [lastAmount, setLastAmount] = useState<string>('');
|
const [lastAmount, setLastAmount] = useState<string>('');
|
||||||
const { tokens } = useEthereum();
|
|
||||||
|
|
||||||
const renderReserveAccounts = tokens
|
|
||||||
.filter(t => (t.tags?.indexOf('longList') || -1) < 0)
|
|
||||||
.map(token => {
|
|
||||||
const mint = token.address;
|
|
||||||
return (
|
|
||||||
<Option
|
|
||||||
key={mint}
|
|
||||||
className="multichain-option"
|
|
||||||
value={mint}
|
|
||||||
name={token.symbol}
|
|
||||||
title={token.name}
|
|
||||||
>
|
|
||||||
<div className="multichain-option-content">
|
|
||||||
<TokenDisplay
|
|
||||||
asset={props.asset}
|
|
||||||
token={token}
|
|
||||||
chain={props.chain}
|
|
||||||
/>
|
|
||||||
<div className="multichain-option-name">
|
|
||||||
<span className={'token-name'}>{token.symbol}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
@ -58,7 +28,9 @@ export function Input(props: {
|
||||||
{!!props.balance && (
|
{!!props.balance && (
|
||||||
<div
|
<div
|
||||||
className="ccy-input-header-right"
|
className="ccy-input-header-right"
|
||||||
onClick={() => props.onInputChange && props.onInputChange(props.balance)}
|
onClick={() =>
|
||||||
|
props.onInputChange && props.onInputChange(props.balance)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Balance: {props.balance.toFixed(6)}
|
Balance: {props.balance.toFixed(6)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,21 +62,11 @@ export function Input(props: {
|
||||||
placeholder="0.00"
|
placeholder="0.00"
|
||||||
/>
|
/>
|
||||||
<div className="ccy-input-header-right" style={{ display: 'flex' }}>
|
<div className="ccy-input-header-right" style={{ display: 'flex' }}>
|
||||||
<Select
|
<TokenSelectModal
|
||||||
size="large"
|
onSelectToken={token => props.setAsset(token)}
|
||||||
showSearch
|
asset={props.asset}
|
||||||
style={{ minWidth: 150 }}
|
chain={props.chain}
|
||||||
placeholder="CCY"
|
/>
|
||||||
value={props.asset}
|
|
||||||
onChange={(item: string) => {
|
|
||||||
props.setAsset(item);
|
|
||||||
}}
|
|
||||||
filterOption={(input, option) =>
|
|
||||||
option?.name?.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{renderReserveAccounts}
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import './style.less';
|
||||||
|
import { Modal, Input } from 'antd';
|
||||||
|
import { useEthereum } from '../../contexts';
|
||||||
|
import { TokenDisplay } from '../TokenDisplay';
|
||||||
|
import { ASSET_CHAIN } from '../../models/bridge/constants';
|
||||||
|
|
||||||
|
export const TokenSelectModal = (props: {
|
||||||
|
onSelectToken: (token: string) => void;
|
||||||
|
asset?: string;
|
||||||
|
chain?: ASSET_CHAIN;
|
||||||
|
}) => {
|
||||||
|
const { tokens } = useEthereum();
|
||||||
|
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
|
||||||
|
const [selected, setSelected] = useState<string>('');
|
||||||
|
const [search, setSearch] = useState<string>('');
|
||||||
|
|
||||||
|
const showModal = () => {
|
||||||
|
setIsModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideModal = () => {
|
||||||
|
setIsModalVisible(false);
|
||||||
|
};
|
||||||
|
const firstToken = useMemo(() => {
|
||||||
|
if (!selected) {
|
||||||
|
return tokens.find(el => el.address === props.asset);
|
||||||
|
}
|
||||||
|
return tokens.find(el => el.address === selected);
|
||||||
|
}, [selected, tokens, props.asset]);
|
||||||
|
|
||||||
|
const renderTokensChain = useMemo(() => {
|
||||||
|
return tokens
|
||||||
|
.filter(
|
||||||
|
t =>
|
||||||
|
(t.tags?.indexOf('longList') || -1) < 0 &&
|
||||||
|
search &&
|
||||||
|
search.length >= 3 &&
|
||||||
|
t.symbol.includes(search.toUpperCase()),
|
||||||
|
)
|
||||||
|
.map(token => {
|
||||||
|
const mint = token.address;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={mint}
|
||||||
|
className="multichain-option"
|
||||||
|
title={token.name}
|
||||||
|
onClick={() => {
|
||||||
|
props.onSelectToken(mint);
|
||||||
|
setSelected(mint);
|
||||||
|
hideModal();
|
||||||
|
}}
|
||||||
|
style={{ cursor: 'pointer' }}
|
||||||
|
>
|
||||||
|
<div className="multichain-option-content">
|
||||||
|
<TokenDisplay
|
||||||
|
asset={props.asset}
|
||||||
|
token={token}
|
||||||
|
chain={props.chain}
|
||||||
|
/>
|
||||||
|
<div className="multichain-option-name">
|
||||||
|
<span className={'token-name'}>{token.symbol}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}, [search, tokens]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{firstToken ? (
|
||||||
|
<div
|
||||||
|
key={firstToken.address}
|
||||||
|
className="multichain-option"
|
||||||
|
title={firstToken.name}
|
||||||
|
onClick={() => showModal()}
|
||||||
|
style={{ cursor: 'pointer' }}
|
||||||
|
>
|
||||||
|
<div className="multichain-option-content">
|
||||||
|
<TokenDisplay
|
||||||
|
asset={props.asset}
|
||||||
|
token={firstToken}
|
||||||
|
chain={props.chain}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<Modal
|
||||||
|
visible={isModalVisible}
|
||||||
|
onCancel={() => hideModal()}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
className={'input-token-search'}
|
||||||
|
placeholder={'ETH, SOL, ... etc'}
|
||||||
|
value={search}
|
||||||
|
onChange={e => setSearch(e.target.value)}
|
||||||
|
/>
|
||||||
|
<div className={'assets-scroll'}>{[...renderTokensChain]}</div>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,7 @@
|
||||||
|
.input-token-search {
|
||||||
|
margin: 20px 0 20px 0;
|
||||||
|
}
|
||||||
|
.assets-scroll {
|
||||||
|
height: 60vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
|
@ -46,13 +46,13 @@ export const Transfer = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(tokens && !request.asset) {
|
if (tokens && !request.asset) {
|
||||||
setRequest({
|
setRequest({
|
||||||
...request,
|
...request,
|
||||||
asset: tokens?.[0]?.address,
|
asset: tokens?.[0]?.address,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [request, tokens, setRequest])
|
}, [request, tokens, setRequest]);
|
||||||
|
|
||||||
const setAssetInformation = async (asset: string) => {
|
const setAssetInformation = async (asset: string) => {
|
||||||
setRequest({
|
setRequest({
|
||||||
|
@ -63,7 +63,7 @@ export const Transfer = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const asset = request.asset;
|
const asset = request.asset;
|
||||||
if(!asset || asset === request?.info?.address) {
|
if (!asset || asset === request?.info?.address) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,9 +87,10 @@ export const Transfer = () => {
|
||||||
address: asset,
|
address: asset,
|
||||||
name: symbol,
|
name: symbol,
|
||||||
balance: balance,
|
balance: balance,
|
||||||
balanceAsNumber: (new BN(balance.toString())
|
balanceAsNumber:
|
||||||
.div(new BN(10).pow(new BN(decimals - 2)))
|
new BN(balance.toString())
|
||||||
.toNumber()) / 100,
|
.div(new BN(10).pow(new BN(decimals - 2)))
|
||||||
|
.toNumber() / 100,
|
||||||
allowance: allowance,
|
allowance: allowance,
|
||||||
decimals: decimals,
|
decimals: decimals,
|
||||||
isWrapped: false,
|
isWrapped: false,
|
||||||
|
@ -103,7 +104,10 @@ export const Transfer = () => {
|
||||||
let isWrapped = await b.isWrappedAsset(asset);
|
let isWrapped = await b.isWrappedAsset(asset);
|
||||||
if (isWrapped) {
|
if (isWrapped) {
|
||||||
info.chainID = await e.assetChain();
|
info.chainID = await e.assetChain();
|
||||||
info.assetAddress = Buffer.from((await e.assetAddress()).slice(2), 'hex');
|
info.assetAddress = Buffer.from(
|
||||||
|
(await e.assetAddress()).slice(2),
|
||||||
|
'hex',
|
||||||
|
);
|
||||||
info.isWrapped = true;
|
info.isWrapped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +117,7 @@ export const Transfer = () => {
|
||||||
info,
|
info,
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
}, [request, provider])
|
}, [request, provider]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -122,7 +126,7 @@ export const Transfer = () => {
|
||||||
title={`From ${chainToName(request.from)}`}
|
title={`From ${chainToName(request.from)}`}
|
||||||
asset={request.asset}
|
asset={request.asset}
|
||||||
chain={request.from}
|
chain={request.from}
|
||||||
balance={request.info?.balanceAsNumber || 0 }
|
balance={request.info?.balanceAsNumber || 0}
|
||||||
setAsset={asset => setAssetInformation(asset)}
|
setAsset={asset => setAssetInformation(asset)}
|
||||||
amount={request.amount}
|
amount={request.amount}
|
||||||
onInputChange={amount => {
|
onInputChange={amount => {
|
||||||
|
@ -179,7 +183,7 @@ export const Transfer = () => {
|
||||||
(async () => {
|
(async () => {
|
||||||
let steps: ProgressUpdate[] = [];
|
let steps: ProgressUpdate[] = [];
|
||||||
try {
|
try {
|
||||||
if(request.toChain === ASSET_CHAIN.Solana) {
|
if (request.toChain === ASSET_CHAIN.Solana) {
|
||||||
await toSolana(
|
await toSolana(
|
||||||
connection,
|
connection,
|
||||||
wallet,
|
wallet,
|
||||||
|
@ -211,8 +215,7 @@ export const Transfer = () => {
|
||||||
request.toChain,
|
request.toChain,
|
||||||
)} Mainnet`}</h5>
|
)} Mainnet`}</h5>
|
||||||
<h2>
|
<h2>
|
||||||
{request.amount?.toString()}{' '}
|
{request.amount?.toString()} {request.info?.name}
|
||||||
{request.info?.name}
|
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -93,7 +93,7 @@ export const EthereumProvider: FunctionComponent = ({ children }) => {
|
||||||
window.ethereum.enable();
|
window.ethereum.enable();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const provider = new ethers.providers.Web3Provider(
|
const provider = new ethers.providers.Web3Provider(
|
||||||
(window as any).ethereum ,
|
(window as any).ethereum,
|
||||||
);
|
);
|
||||||
const signer = provider.getSigner();
|
const signer = provider.getSigner();
|
||||||
signer.getAddress().then(account => setAccounts([account]));
|
signer.getAddress().then(account => setAccounts([account]));
|
||||||
|
|
Loading…
Reference in New Issue