bridge_ui: ethereum token selector utilizes covalent
Change-Id: I2f9fdebb9e80c414281005c2659ba47c7ef4b75d
This commit is contained in:
parent
49d41733a7
commit
b6771f291d
|
@ -31,6 +31,7 @@
|
|||
"@solana/wallet-base": "^0.0.1",
|
||||
"@solana/web3.js": "^1.24.1",
|
||||
"@terra-money/wallet-provider": "^1.4.0-alpha.1",
|
||||
"axios": "^0.21.1",
|
||||
"bech32": "^1.1.4",
|
||||
"bn.js": "^5.1.3",
|
||||
"borsh": "^0.4.0",
|
||||
|
@ -65,6 +66,7 @@
|
|||
"@solana/web3.js": "^1.24.0",
|
||||
"@terra-money/terra.js": "^1.8.10",
|
||||
"@terra-money/wallet-provider": "^1.2.4",
|
||||
"bech32": "^2.0.0",
|
||||
"js-base64": "^3.6.1",
|
||||
"protobufjs": "^6.11.2",
|
||||
"rxjs": "^7.3.0"
|
||||
|
@ -6402,14 +6404,6 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@terra-money/terra.js/node_modules/axios": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@terra-money/terra.js/node_modules/bech32": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
|
||||
|
@ -8818,6 +8812,17 @@
|
|||
"secp256k1": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@zondax/filecoin-signing-tools/node_modules/axios": {
|
||||
"version": "0.20.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
|
||||
"integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==",
|
||||
"deprecated": "Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@zxing/text-encoding": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
|
||||
|
@ -9983,12 +9988,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.20.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
|
||||
"integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==",
|
||||
"deprecated": "Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
|
@ -41073,6 +41075,7 @@
|
|||
"@types/long": "^4.0.1",
|
||||
"@types/node": "^16.6.1",
|
||||
"@types/react": "^17.0.19",
|
||||
"bech32": "^2.0.0",
|
||||
"copy-dir": "^1.3.0",
|
||||
"ethers": "^5.4.4",
|
||||
"js-base64": "^3.6.1",
|
||||
|
@ -44375,14 +44378,6 @@
|
|||
"ws": "^7.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"bech32": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
|
||||
|
@ -46618,6 +46613,18 @@
|
|||
"ipld-dag-cbor": "^0.17.0",
|
||||
"leb128": "0.0.5",
|
||||
"secp256k1": "^4.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": {
|
||||
"version": "0.20.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
|
||||
"integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@zxing/text-encoding": {
|
||||
|
@ -47517,11 +47524,9 @@
|
|||
"integrity": "sha512-3WVgVPs/7OnKU3s+lqMtkv3wQlg3WxK1YifmpJSDO0E1aPBrZWlrrTO6cxRqCXLuX2aYgCljqXIQd0VnRidV0g=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.20.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
|
||||
"integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
"@solana/wallet-base": "^0.0.1",
|
||||
"@solana/web3.js": "^1.24.1",
|
||||
"@terra-money/wallet-provider": "^1.4.0-alpha.1",
|
||||
"axios": "^0.21.1",
|
||||
"bech32": "^1.1.4",
|
||||
"bn.js": "^5.1.3",
|
||||
"borsh": "^0.4.0",
|
||||
|
|
|
@ -1,23 +1,75 @@
|
|||
import { Button, TextField, Typography } from "@material-ui/core";
|
||||
import {
|
||||
Button,
|
||||
CircularProgress,
|
||||
createStyles,
|
||||
makeStyles,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@material-ui/core";
|
||||
import { Autocomplete, createFilterOptions } from "@material-ui/lab";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { useEthereumProvider } from "../../contexts/EthereumProviderContext";
|
||||
import { CovalentData } from "../../hooks/useGetSourceParsedTokenAccounts";
|
||||
import { DataWrapper } from "../../store/helpers";
|
||||
import { ParsedTokenAccount } from "../../store/transferSlice";
|
||||
import {
|
||||
ethTokenToParsedTokenAccount,
|
||||
getEthereumToken,
|
||||
isValidEthereumAddress,
|
||||
} from "../../utils/ethereum";
|
||||
import { shortenAddress } from "../../utils/solana";
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
selectInput: { minWidth: "10rem" },
|
||||
tokenOverviewContainer: {
|
||||
display: "flex",
|
||||
"& div": {
|
||||
margin: ".5rem",
|
||||
},
|
||||
},
|
||||
tokenImage: {
|
||||
maxHeight: "2.5rem", //Eyeballing this based off the text size
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
type EthereumSourceTokenSelectorProps = {
|
||||
value: ParsedTokenAccount | null;
|
||||
onChange: (newValue: ParsedTokenAccount | null) => void;
|
||||
covalent: DataWrapper<CovalentData[]> | undefined;
|
||||
tokenAccounts: DataWrapper<ParsedTokenAccount[]> | undefined;
|
||||
};
|
||||
|
||||
const renderAccount = (
|
||||
account: ParsedTokenAccount,
|
||||
covalentData: CovalentData | undefined,
|
||||
classes: any
|
||||
) => {
|
||||
const mintPrettyString = shortenAddress(account.mintKey);
|
||||
const uri = covalentData?.logo_url;
|
||||
const symbol = covalentData?.contract_ticker_symbol || "Unknown";
|
||||
return (
|
||||
<div className={classes.tokenOverviewContainer}>
|
||||
<div>
|
||||
{uri && <img alt="" className={classes.tokenImage} src={uri} />}
|
||||
</div>
|
||||
<div>
|
||||
<Typography variant="subtitle1">{symbol}</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Typography variant="body1">{mintPrettyString}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function EthereumSourceTokenSelector(
|
||||
props: EthereumSourceTokenSelectorProps
|
||||
) {
|
||||
const { onChange, value } = props;
|
||||
const advancedMode = true; //const [advancedMode, setAdvancedMode] = useState(true);
|
||||
const { value, onChange, covalent, tokenAccounts } = props;
|
||||
const classes = useStyles();
|
||||
const [advancedMode, setAdvancedMode] = useState(false);
|
||||
const [advancedModeLoading, setAdvancedModeLoading] = useState(false);
|
||||
const [advancedModeSymbol, setAdvancedModeSymbol] = useState("");
|
||||
const [advancedModeHolderString, setAdvancedModeHolderString] = useState("");
|
||||
|
@ -91,8 +143,6 @@ export default function EthereumSourceTokenSelector(
|
|||
onChange,
|
||||
]);
|
||||
|
||||
const symbolString = advancedModeSymbol ? advancedModeSymbol + " " : "";
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
onChange(null);
|
||||
setAdvancedModeHolderString("");
|
||||
|
@ -103,16 +153,88 @@ export default function EthereumSourceTokenSelector(
|
|||
[]
|
||||
);
|
||||
|
||||
const getSymbol = (account: ParsedTokenAccount | null) => {
|
||||
if (!account) {
|
||||
return undefined;
|
||||
}
|
||||
return covalent?.data?.find((x) => x.contract_address === account.mintKey);
|
||||
};
|
||||
|
||||
const filterConfig = createFilterOptions({
|
||||
matchFrom: "any",
|
||||
stringify: (option: ParsedTokenAccount) => {
|
||||
const symbol = getSymbol(option) + " " || "";
|
||||
const mint = option.mintKey + " ";
|
||||
|
||||
return symbol + mint;
|
||||
},
|
||||
});
|
||||
|
||||
const toggleAdvancedMode = () => {
|
||||
setAdvancedMode(!advancedMode);
|
||||
};
|
||||
|
||||
const isLoading =
|
||||
props.covalent?.isFetching || props.tokenAccounts?.isFetching;
|
||||
|
||||
const symbolString = advancedModeSymbol
|
||||
? advancedModeSymbol + " "
|
||||
: getSymbol(value)
|
||||
? getSymbol(value)?.contract_ticker_symbol + " "
|
||||
: "";
|
||||
|
||||
const autoComplete = (
|
||||
<Autocomplete
|
||||
autoComplete
|
||||
autoHighlight
|
||||
autoSelect
|
||||
blurOnSelect
|
||||
clearOnBlur
|
||||
fullWidth={false}
|
||||
filterOptions={filterConfig}
|
||||
value={value}
|
||||
onChange={(event, newValue) => {
|
||||
onChange(newValue);
|
||||
}}
|
||||
noOptionsText={"No ERC20 tokens found at the moment."}
|
||||
options={tokenAccounts?.data || []}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Token Account" variant="outlined" />
|
||||
)}
|
||||
renderOption={(option) => {
|
||||
return renderAccount(
|
||||
option,
|
||||
covalent?.data?.find((x) => x.contract_address === option.mintKey),
|
||||
classes
|
||||
);
|
||||
}}
|
||||
getOptionLabel={(option) => {
|
||||
const symbol = getSymbol(option);
|
||||
return `${symbol ? symbol : "Unknown"} (Account: ${shortenAddress(
|
||||
option.publicKey
|
||||
)}, Address: ${shortenAddress(option.mintKey)})`;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const advancedModeToggleButton = (
|
||||
<Button onClick={toggleAdvancedMode}>
|
||||
{advancedMode ? "Toggle Token Picker" : "Toggle Override"}
|
||||
</Button>
|
||||
);
|
||||
|
||||
const content = value ? (
|
||||
<>
|
||||
<Typography>{symbolString + value.mintKey}</Typography>
|
||||
<Button onClick={handleClick}>Clear</Button>
|
||||
</>
|
||||
) : (
|
||||
) : isLoading ? (
|
||||
<CircularProgress />
|
||||
) : advancedMode ? (
|
||||
<>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Asset Address"
|
||||
label="Enter an asset address"
|
||||
value={advancedModeHolderString}
|
||||
onChange={handleOnChange}
|
||||
error={
|
||||
|
@ -124,7 +246,14 @@ export default function EthereumSourceTokenSelector(
|
|||
disabled={advancedModeLoading}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
autoComplete
|
||||
);
|
||||
|
||||
return <React.Fragment>{content}</React.Fragment>;
|
||||
return (
|
||||
<React.Fragment>
|
||||
{content}
|
||||
{!value && !isLoading && advancedModeToggleButton}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,10 @@ export const TokenSelector = (props: TokenSelectorProps) => {
|
|||
const maps = useGetSourceParsedTokens();
|
||||
|
||||
//This is only for errors so bad that we shouldn't even mount the component
|
||||
const fatalError = maps?.tokenAccounts?.error;
|
||||
const fatalError =
|
||||
maps?.tokenAccounts?.error &&
|
||||
!(lookupChain === CHAIN_ID_ETH) &&
|
||||
!(lookupChain === CHAIN_ID_TERRA); //Terra & ETH can proceed because it has advanced mode
|
||||
|
||||
const content = fatalError ? (
|
||||
<Typography>{fatalError}</Typography>
|
||||
|
@ -59,6 +62,8 @@ export const TokenSelector = (props: TokenSelectorProps) => {
|
|||
<EthereumSourceTokenSelector
|
||||
value={sourceParsedTokenAccount || null}
|
||||
onChange={handleSolanaOnChange}
|
||||
covalent={maps?.covalent || undefined}
|
||||
tokenAccounts={maps?.tokenAccounts} //TODO standardize
|
||||
/>
|
||||
) : lookupChain === CHAIN_ID_TERRA ? (
|
||||
<TerraSourceTokenSelector
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
import {
|
||||
CHAIN_ID_ETH,
|
||||
CHAIN_ID_SOLANA,
|
||||
TokenImplementation__factory,
|
||||
} from "@certusone/wormhole-sdk";
|
||||
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
|
||||
import { Dispatch } from "@reduxjs/toolkit";
|
||||
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import { ENV, TokenListProvider } from "@solana/spl-token-registry";
|
||||
|
@ -12,6 +8,7 @@ import {
|
|||
ParsedAccountData,
|
||||
PublicKey,
|
||||
} from "@solana/web3.js";
|
||||
import axios from "axios";
|
||||
import { formatUnits } from "ethers/lib/utils";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
@ -33,9 +30,8 @@ import {
|
|||
fetchSourceParsedTokenAccounts,
|
||||
ParsedTokenAccount,
|
||||
receiveSourceParsedTokenAccounts,
|
||||
setSourceParsedTokenAccount,
|
||||
} from "../store/transferSlice";
|
||||
import { ETH_TEST_TOKEN_ADDRESS, SOLANA_HOST } from "../utils/consts";
|
||||
import { COVALENT_GET_TOKENS_URL, SOLANA_HOST } from "../utils/consts";
|
||||
import {
|
||||
decodeMetadata,
|
||||
getMetadataAddress,
|
||||
|
@ -75,6 +71,62 @@ const createParsedTokenAccountFromInfo = (
|
|||
};
|
||||
};
|
||||
|
||||
const createParsedTokenAccountFromCovalent = (
|
||||
walletAddress: string,
|
||||
covalent: CovalentData
|
||||
): ParsedTokenAccount => {
|
||||
return {
|
||||
publicKey: walletAddress,
|
||||
mintKey: covalent.contract_address,
|
||||
amount: covalent.balance,
|
||||
decimals: covalent.contract_decimals,
|
||||
uiAmount: Number(formatUnits(covalent.balance, covalent.contract_decimals)),
|
||||
uiAmountString: formatUnits(covalent.balance, covalent.contract_decimals),
|
||||
};
|
||||
};
|
||||
|
||||
export type CovalentData = {
|
||||
contract_decimals: number;
|
||||
contract_ticker_symbol: string;
|
||||
contract_name: string;
|
||||
contract_address: string;
|
||||
logo_url: string | undefined;
|
||||
balance: string;
|
||||
quote: number | undefined;
|
||||
quote_rate: number | undefined;
|
||||
};
|
||||
|
||||
const getEthereumAccountsCovalent = async (
|
||||
walletAddress: string
|
||||
): Promise<CovalentData[]> => {
|
||||
const url = COVALENT_GET_TOKENS_URL(CHAIN_ID_ETH, walletAddress);
|
||||
|
||||
try {
|
||||
const output = [] as CovalentData[];
|
||||
const response = await axios.get(url);
|
||||
const tokens = response.data.data.items;
|
||||
|
||||
if (tokens instanceof Array && tokens.length) {
|
||||
for (const item of tokens) {
|
||||
if (
|
||||
item.contract_decimals &&
|
||||
item.contract_ticker_symbol &&
|
||||
item.contract_address &&
|
||||
item.balance &&
|
||||
item.supports_erc?.includes("erc20")
|
||||
) {
|
||||
output.push({ ...item } as CovalentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return Promise.reject("Unable to retrieve your Ethereum Tokens.");
|
||||
}
|
||||
};
|
||||
|
||||
const environment =
|
||||
process.env.REACT_APP_CLUSTER === "testnet" ? ENV.Testnet : ENV.MainnetBeta;
|
||||
|
||||
|
@ -166,10 +218,16 @@ function useGetAvailableTokens() {
|
|||
//const terraWallet = useConnectedWallet(); //TODO
|
||||
const { provider, signerAddress } = useEthereumProvider();
|
||||
|
||||
const [metaplex, setMetaplex] = useState(undefined as any);
|
||||
const [metaplex, setMetaplex] = useState<any>(undefined);
|
||||
const [metaplexLoading, setMetaplexLoading] = useState(false);
|
||||
const [metaplexError, setMetaplexError] = useState(null);
|
||||
|
||||
const [covalent, setCovalent] = useState<any>(undefined);
|
||||
const [covalentLoading, setCovalentLoading] = useState(false);
|
||||
const [covalentError, setCovalentError] = useState<string | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
// Solana metaplex load
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
@ -234,51 +292,42 @@ function useGetAvailableTokens() {
|
|||
//Ethereum accounts load
|
||||
//TODO actual load from covalent. This is just a hardcoded testing load
|
||||
useEffect(() => {
|
||||
//const testWallet = "0xf60c2ea62edbfe808163751dd0d8693dcb30019c";
|
||||
let cancelled = false;
|
||||
if (lookupChain === CHAIN_ID_ETH && provider && signerAddress) {
|
||||
const token = TokenImplementation__factory.connect(
|
||||
ETH_TEST_TOKEN_ADDRESS,
|
||||
provider
|
||||
);
|
||||
token
|
||||
.decimals()
|
||||
.then((decimals) => {
|
||||
token.balanceOf(signerAddress).then((n) => {
|
||||
if (!cancelled) {
|
||||
const walletAddress = signerAddress;
|
||||
if (!walletAddress) {
|
||||
return;
|
||||
}
|
||||
//TODO less cancel
|
||||
!cancelled && setCovalentLoading(true);
|
||||
!cancelled && dispatch(fetchSourceParsedTokenAccounts());
|
||||
getEthereumAccountsCovalent(walletAddress).then(
|
||||
(accounts) => {
|
||||
!cancelled && setCovalentLoading(false);
|
||||
!cancelled && setCovalentError(undefined);
|
||||
!cancelled && setCovalent(accounts);
|
||||
!cancelled &&
|
||||
dispatch(
|
||||
setSourceParsedTokenAccount(
|
||||
createParsedTokenAccount(
|
||||
signerAddress,
|
||||
ETH_TEST_TOKEN_ADDRESS,
|
||||
n.toString(),
|
||||
decimals,
|
||||
Number(formatUnits(n, decimals)),
|
||||
formatUnits(n, decimals)
|
||||
receiveSourceParsedTokenAccounts(
|
||||
accounts.map((x) =>
|
||||
createParsedTokenAccountFromCovalent(walletAddress, x)
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
() => {
|
||||
!cancelled &&
|
||||
dispatch(
|
||||
receiveSourceParsedTokenAccounts([
|
||||
createParsedTokenAccount(
|
||||
signerAddress,
|
||||
ETH_TEST_TOKEN_ADDRESS,
|
||||
n.toString(),
|
||||
decimals,
|
||||
Number(formatUnits(n, decimals)),
|
||||
formatUnits(n, decimals)
|
||||
),
|
||||
])
|
||||
errorSourceParsedTokenAccounts(
|
||||
"Cannot load your Ethereum tokens at the moment."
|
||||
)
|
||||
);
|
||||
!cancelled &&
|
||||
setCovalentError("Cannot load your Ethereum tokens at the moment.");
|
||||
!cancelled && setCovalentLoading(false);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
if (!cancelled) {
|
||||
// TODO: error state
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
|
@ -301,6 +350,16 @@ function useGetAvailableTokens() {
|
|||
receivedAt: null, //TODO
|
||||
} as DataWrapper<Metadata[]>,
|
||||
}
|
||||
: lookupChain === CHAIN_ID_ETH
|
||||
? {
|
||||
tokenAccounts: tokenAccounts,
|
||||
covalent: {
|
||||
data: covalent,
|
||||
isFetching: covalentLoading,
|
||||
error: covalentError,
|
||||
receivedAt: null, //TODO
|
||||
},
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,3 +93,21 @@ export const TERRA_BRIDGE_ADDRESS =
|
|||
"terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5";
|
||||
export const TERRA_TOKEN_BRIDGE_ADDRESS =
|
||||
"terra10pyejy66429refv3g35g2t7am0was7ya7kz2a4";
|
||||
|
||||
export const COVALENT_API_KEY = process.env.REACT_APP_COVALENT_API_KEY
|
||||
? process.env.REACT_APP_COVALENT_API_KEY
|
||||
: "";
|
||||
|
||||
export const COVALENT_GET_TOKENS_URL = (
|
||||
chainId: ChainId,
|
||||
walletAddress: string
|
||||
) => {
|
||||
let chainNum = "";
|
||||
if (chainId === CHAIN_ID_ETH) {
|
||||
chainNum = COVALENT_ETHEREUM_MAINNET;
|
||||
}
|
||||
|
||||
return `https://api.covalenthq.com/v1/${chainNum}/address/${walletAddress}/balances_v2/?key=${COVALENT_API_KEY}`;
|
||||
};
|
||||
|
||||
export const COVALENT_ETHEREUM_MAINNET = "1";
|
||||
|
|
Loading…
Reference in New Issue