diff --git a/packages/react-app/package.json b/packages/react-app/package.json
index fe83752..e981a38 100644
--- a/packages/react-app/package.json
+++ b/packages/react-app/package.json
@@ -54,6 +54,7 @@
"react-qr-reader": "^2.2.1",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.0",
+ "searchico": "^1.2.1",
"walletlink": "^2.1.5",
"web3modal": "^1.9.1"
},
diff --git a/packages/react-app/src/components/TokenSelect.jsx b/packages/react-app/src/components/TokenSelect.jsx
new file mode 100644
index 0000000..64161f8
--- /dev/null
+++ b/packages/react-app/src/components/TokenSelect.jsx
@@ -0,0 +1,151 @@
+import { Select } from "antd";
+import { useState, useMemo, useEffect } from "react";
+import { ethers } from "ethers";
+import axios from "axios";
+import searchico from "searchico";
+
+// helpers to load token name and symbol for unlisted tokens
+const ERC20ABI = ["function symbol() view returns (string)", "function name() view returns (string)"];
+
+const loadERC20 = async (address, p) => {
+ try {
+ // load token information here
+ const r = new ethers.Contract(address, ERC20ABI, p);
+ const name = await r.name?.();
+ const symbol = await r.symbol?.();
+
+ return { name, symbol };
+ } catch (error) {
+ return {};
+ }
+};
+
+/*
+
+*/
+export default function TokenSelect({ onChange, chainId = 1, nativeToken = {}, localProvider, ...props }) {
+ const [value, setValue] = useState(null);
+ const [list, setList] = useState([]);
+ const [searchResults, setSearchResults] = useState([]);
+
+ const listCollection = useMemo(() => {
+ return searchico(list, { keys: ["address", "name", "symbol"] });
+ }, [list.length]);
+
+ const children = useMemo(() => {
+ if (searchResults.length < 1) {
+ return [];
+ }
+
+ // use search result to format children
+ return searchResults.map(i => (
+
+
+ {i.logoURI && (
+
+
![{`${i.name}]({i.logoURI})
+
+ )}
+ {i.name} - {i.symbol} {i.address?.substr(0, 5) + "..." + i.address?.substr(-4)}{" "}
+ {i.unlisted &&
(unlisted) }
+
+
+ ));
+ }, [JSON.stringify(searchResults)]);
+
+ const handleSearch = async val => {
+ let collectionResult = [];
+
+ if (val.length > 0) {
+ // TODO : Do all search & filtering here
+ collectionResult = (listCollection?.find(val) || []).filter(i => i.chainId === chainId);
+
+ if (collectionResult.length < 1) {
+ const nativeTokenObj = {
+ chainId: chainId,
+ decimals: 18,
+ name: "Default Token",
+ symbol: "GTC",
+ address: "0xde30da39c46104798bb5aa3fe8b9e0e1f348163f",
+ logoURI: "https://assets.coingecko.com/coins/images/15810/thumb/gitcoin.png?1621992929",
+ ...nativeToken,
+ };
+
+ collectionResult.push(nativeTokenObj);
+
+ try {
+ const checksumAddress = ethers.utils.getAddress(val);
+ // load contract and try to get name and symbol if there's a provider given
+ const tokenInfo = localProvider ? await loadERC20(checksumAddress, localProvider) : {};
+ collectionResult = [
+ {
+ chainId: chainId,
+ name: null,
+ unlisted: true,
+ symbol: null,
+ address: checksumAddress,
+ logoURI: "",
+ ...tokenInfo,
+ },
+ ];
+ } catch (error) {
+ console.log(`Could not identify this token`);
+ }
+ }
+ }
+
+ setSearchResults(collectionResult);
+ };
+
+ const handleOnChange = async e => {
+ setSearchResults([]);
+
+ // TODO : check if it's an address that's not on list & Add as unlisted
+
+ setValue(e);
+
+ if (typeof onChange === "function") {
+ onChange(e.value);
+ }
+ };
+
+ const loadList = async () => {
+ // https://tokens.coingecko.com/uniswap/all.json
+ const res = await axios.get("https://tokens.coingecko.com/uniswap/all.json");
+ const { tokens } = res.data;
+
+ setList(tokens);
+ };
+
+ useEffect(() => {
+ loadList();
+ }, []);
+
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/packages/react-app/src/components/index.js b/packages/react-app/src/components/index.js
index 3306839..68a2f17 100644
--- a/packages/react-app/src/components/index.js
+++ b/packages/react-app/src/components/index.js
@@ -15,6 +15,7 @@ export { default as Swap } from "./Swap";
export { default as ThemeSwitch } from "./ThemeSwitch";
export { default as Timeline } from "./Timeline";
export { default as TokenBalance } from "./TokenBalance";
+export { default as TokenSelect } from "./TokenSelect";
export { default as Wallet } from "./Wallet";
export { default as L2Bridge } from "./L2Bridge";
export { default as QRBlockie } from "./QRBlockie";
diff --git a/packages/react-app/src/views/Home.jsx b/packages/react-app/src/views/Home.jsx
index 78965bd..5f9e3e3 100644
--- a/packages/react-app/src/views/Home.jsx
+++ b/packages/react-app/src/views/Home.jsx
@@ -11,11 +11,14 @@ import {
Col,
Progress,
Spin,
+ Popover,
} from "antd";
-import { AddressInput, Address, Balance } from "../components";
+import { AddressInput, Address, Balance, TokenSelect } from "../components";
+import { InfoCircleOutlined } from "@ant-design/icons";
import { SimpleStreamABI } from "../contracts/external_ABI";
import { useHistory } from "react-router";
import { Link } from "react-router-dom";
+import axios from "axios";
export default function Home({
mainnetProvider,
@@ -35,10 +38,20 @@ export default function Home({
const [sData, setData] = useState([]);
+ const [tokenAddress, setTokenAddress] = useState("0xde30da39c46104798bb5aa3fe8b9e0e1f348163f");
+ const [tokenPrice, setTokenPrice] = useState(0);
+
let copy = JSON.parse(JSON.stringify(streams));
+ const getTokenPrice = async (address) => {
+ const res = await axios.get(`https://api.coingecko.com/api/v3/simple/token_price/ethereum?contract_addresses=${address}&vs_currencies=usd`);
+ const price = res.data[address]['usd'];
+ setTokenPrice(price);
+ }
+
useEffect(async () => {
// Get an instance for each Stream contract
+ getTokenPrice(tokenAddress);
for (let b in streams) {
if (streams)
var contract = new ethers.Contract(
@@ -75,8 +88,6 @@ export default function Home({
"604800"
);
const _startFull = startFull === 1;
- const GTCContractAddress = readContracts && readContracts.GTC.address;
-
const result = tx(
writeContracts &&
writeContracts.StreamFactory.createStreamFor(
@@ -84,7 +95,7 @@ export default function Home({
capFormatted,
frequencyFormatted,
_startFull,
- GTCContractAddress
+ tokenAddress
),
async (update) => {
console.log("📡 Transaction Update:", update);
@@ -121,6 +132,18 @@ export default function Home({
console.log(await result);
};
+ const setToAddress = (address) => {
+ setTokenAddress(address);
+ getTokenPrice(address);
+ }
+
+ const minimumAmount = () => {
+ // Minimum 10 USD for a stream
+ return parseFloat(10/tokenPrice).toFixed(2);
+ }
+
+ const content = (Default Token: GTC
);
+
return (
setUserAddress(a)}
/>
+
+
+
-
GTC Amount:
+
Amount:
setAmount(v)}
style={{ width: "100%" }}