This commit is contained in:
bartosz-lipinski 2021-03-11 14:49:44 -06:00
commit c2426bf916
7 changed files with 105 additions and 42 deletions

View File

@ -12,6 +12,7 @@ export function Input(props: {
chain?: ASSET_CHAIN;
setAsset: (asset: string) => void;
amount?: number | null;
onChain: (chain: ASSET_CHAIN) => void;
onInputChange: (value: number | undefined) => void;
}) {
const [lastAmount, setLastAmount] = useState<string>('');
@ -64,6 +65,7 @@ export function Input(props: {
<div className="ccy-input-header-right" style={{ display: 'flex' }}>
<TokenSelectModal
onSelectToken={token => props.setAsset(token)}
onChain={(chain: ASSET_CHAIN) => props.onChain(chain)}
asset={props.asset}
chain={props.chain}
/>

View File

@ -1,22 +1,32 @@
import React, { useMemo, useState } from 'react';
import React, { useMemo, useRef, useState } from 'react';
import List from 'react-virtualized/dist/commonjs/List';
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
import _ from 'lodash';
import './style.less';
import { Modal, Input } from 'antd';
import { Input, Modal } from 'antd';
import { useEthereum } from '../../contexts';
import { TokenDisplay } from '../TokenDisplay';
import { ASSET_CHAIN } from '../../models/bridge/constants';
import { useConnectionConfig } from '@oyster/common';
import { filterModalSolTokens } from '../../utils/assets';
export const TokenSelectModal = (props: {
onSelectToken: (token: string) => void;
onChain: (chain: ASSET_CHAIN) => void;
asset?: string;
chain?: ASSET_CHAIN;
}) => {
const { tokens } = useEthereum();
const { tokens: ethTokens } = useEthereum();
const { tokens: solTokens } = useConnectionConfig();
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
const [search, setSearch] = useState<string>('');
const inputRef = useRef<Input>(null);
const tokens = useMemo(
() => [...ethTokens, ...filterModalSolTokens(solTokens)],
[ethTokens, solTokens],
);
const tokenList = useMemo(() => {
if (tokens && search) {
return tokens.filter(token => {
@ -30,6 +40,9 @@ export const TokenSelectModal = (props: {
}, [tokens, search]);
const showModal = () => {
if (inputRef && inputRef.current) {
setTimeout(() => inputRef.current?.focus(), 300);
}
setIsModalVisible(true);
};
@ -47,29 +60,40 @@ export const TokenSelectModal = (props: {
const rowRender = (rowProps: { index: number; key: string; style: any }) => {
const token = tokenList[rowProps.index];
const mint = token.address;
return (
<div
key={rowProps.key}
className="multichain-option"
title={token.name}
onClick={() => {
props.onSelectToken(mint);
hideModal();
}}
style={{ ...rowProps.style, cursor: 'pointer' }}
>
<div className="multichain-option-content">
<TokenDisplay asset={props.asset} token={token} chain={props.chain} />
return [ASSET_CHAIN.Solana, ASSET_CHAIN.Ethereum].map((chain, index) => {
return (
<div
key={rowProps.key + mint + chain}
className="multichain-option"
title={token.name}
onClick={() => {
props.onSelectToken(mint);
props.onChain(chain);
hideModal();
}}
style={{
...rowProps.style,
cursor: 'pointer',
height: '70px',
top: `${rowProps.style.top + 70 * index}px`,
}}
>
<div
className="multichain-option-name"
style={{ marginLeft: '20px' }}
className="multichain-option-content"
style={{ position: 'relative' }}
>
<em className={'token-symbol'}>{token.symbol}</em>
<span className={'token-name'}>{token.name}</span>
<TokenDisplay asset={props.asset} token={token} chain={chain} />
<div
className="multichain-option-name"
style={{ marginLeft: '20px' }}
>
<em className={'token-symbol'}>{token.symbol}</em>
<span className={'token-name'}>{token.name}</span>
</div>
</div>
</div>
</div>
);
);
});
};
return (
@ -97,6 +121,8 @@ export const TokenSelectModal = (props: {
footer={null}
>
<Input
autoFocus
ref={inputRef}
className={'input-token-search'}
placeholder={'SOL, SRM, ... etc'}
value={search}
@ -111,7 +137,7 @@ export const TokenSelectModal = (props: {
<List
ref="List"
height={height}
rowHeight={70}
rowHeight={140}
rowCount={tokenList.length || 0}
rowRenderer={rowRender}
width={width}

View File

@ -5,7 +5,9 @@
height: 60vh;
overflow: auto;
}
.multichain-option:hover {
background-color: rgba(255, 255, 255, 0.08);
}
.ant-modal-body {
height: 80vh;
::-webkit-scrollbar-track {
@ -13,7 +15,7 @@
background-color: transparent;
}
::-webkit-scrollbar {
width: 7px;
width: 10px;
background-color: transparent;
}
::-webkit-scrollbar-thumb {
@ -23,3 +25,7 @@
background-color: #555;
}
}
.ReactVirtualized__Grid.ReactVirtualized__List:focus {
outline: none !important;
}

View File

@ -148,6 +148,11 @@ export const Transfer = () => {
setAsset={asset => setAssetInformation(asset)}
chain={A.chain}
amount={A.amount}
onChain={(chain: ASSET_CHAIN) => {
const from = A.chain;
A.setChain(chain);
B.setChain(from);
}}
onInputChange={amount => {
setLastTypedAccount(A.chain);
A.setAmount(amount || 0);
@ -156,6 +161,7 @@ export const Transfer = () => {
<Button
type="primary"
className="swap-button"
style={{ paddingLeft: '11px' }}
disabled={false}
onClick={() => {
const from = A.chain;
@ -174,6 +180,11 @@ export const Transfer = () => {
setAsset={asset => setAssetInformation(asset)}
chain={B.chain}
amount={B.amount}
onChain={(chain: ASSET_CHAIN) => {
const to = B.chain;
B.setChain(chain);
A.setChain(to);
}}
onInputChange={amount => {
setLastTypedAccount(B.chain);
B.setAmount(amount || 0);
@ -245,7 +256,9 @@ export const Transfer = () => {
<div>
<div style={{ display: 'flex' }}>
<div>
<h5>{`${chainToName(request.from)} Mainnet -> ${chainToName(request.toChain)} Mainnet`}</h5>
<h5>{`${chainToName(request.from)} Mainnet -> ${chainToName(
request.toChain,
)} Mainnet`}</h5>
<h2>
{request.amount?.toString()} {request.info?.name}
</h2>

View File

@ -7,9 +7,9 @@ import React, {
} from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import bs58 from 'bs58';
import { useConnection } from '@oyster/common';
import { useConnection, useConnectionConfig } from '@oyster/common';
import { TokenInfo } from '@solana/spl-token-registry';
import { ASSET_CHAIN } from '../utils/assets';
import { ASSET_CHAIN, filterModalSolTokens } from '../utils/assets';
import { useEthereum } from './ethereum';
export interface TokenChainContextState {
@ -88,7 +88,8 @@ export const useCurrencyLeg = () => {
};
export function TokenChainPairProvider({ children = null as any }) {
const { tokens } = useEthereum();
const { tokens: ethTokens } = useEthereum();
const { tokens: solTokens } = useConnectionConfig();
const history = useHistory();
const location = useLocation();
@ -107,6 +108,11 @@ export function TokenChainPairProvider({ children = null as any }) {
const chainB = quote.chain;
const setChainB = quote.setChain;
const tokens = useMemo(
() => [...ethTokens, ...filterModalSolTokens(solTokens)],
[ethTokens, solTokens],
);
// updates browser history on token changes
useEffect(() => {
// set history

View File

@ -50,13 +50,17 @@ export const EthereumProvider: FunctionComponent = ({ children }) => {
(async () => {
const map = new Map<string, TokenInfo>();
const listResponse: TokenList[] = await Promise.all([
fetch('https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/tokenlist.json').then(_ =>
_.json(),
).catch(_ => []),
fetch('https://tokenlist.aave.eth.link/').then(_ => _.json()).catch(() => []),
fetch('https://tokens.coingecko.com/uniswap/all.json').then(_ =>
_.json(),
).catch(() => []),
fetch(
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/tokenlist.json',
)
.then(_ => _.json())
.catch(_ => ({ tokens: [] })),
fetch('https://tokenlist.aave.eth.link/')
.then(_ => _.json())
.catch(() => ({ tokens: [] })),
fetch('https://tokens.coingecko.com/uniswap/all.json')
.then(_ => _.json())
.catch(() => ({ tokens: [] })),
]);
listResponse.forEach((list, i) =>
@ -67,12 +71,14 @@ export const EthereumProvider: FunctionComponent = ({ children }) => {
const item = {
...val,
logoURI: current?.logoURI || (val.logoURI
? val.logoURI?.replace(
'ipfs://',
'https://cloudflare-ipfs.com/ipfs/',
)
: ` https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/${val.address}/logo.png`),
logoURI:
current?.logoURI ||
(val.logoURI
? val.logoURI?.replace(
'ipfs://',
'https://cloudflare-ipfs.com/ipfs/',
)
: ` https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/${val.address}/logo.png`),
tags: val.tags ? [...val.tags, extraTag] : [extraTag],
};

View File

@ -47,3 +47,7 @@ const CHAIN_NAME = {
export const chainToName = (chain?: ASSET_CHAIN) => {
return CHAIN_NAME[chain || ASSET_CHAIN.Ethereum];
};
export const filterModalSolTokens = (tokens: any[]) => {
return tokens;
};