I made a custom component for doing this:
import InchDexCustom from "components/InchDex/InchDexCustom";
<InchDexCustom chain="bsc" toTokenAddress="0xc66c...f9b2de" slippage={12}/>
How to use:
Change line 78 of useInchDex.js hook:
from
slippage: 1,
to
slippage: params.newslippage ? params.newslippage : 1,
Add this file to the InchDex folder in components:
InchDexCustom.jsx
import { useState, useEffect, useMemo } from "react";
import { useMoralis, useWeb3Contract } from "react-moralis";
import { useMoralisDapp } from "providers/MoralisDappProvider/MoralisDappProvider";
import InchModal from "./components/InchModal";
import useInchDex from "hooks/useInchDex";
import { Button, Card, Image, Input, InputNumber, Modal } from "antd";
import Text from "antd/lib/typography/Text";
import { ArrowDownOutlined } from "@ant-design/icons";
import useTokenPrice from "hooks/useTokenPrice";
import { tokenValue } from "helpers/formatters";
//import erc20Abi from "./contractAbi/standardErc20Abi"
// import { useOneInchQuote } from "react-moralis";
const styles = {
card: {
width: "430px",
boxShadow: "0 0.5rem 1.2rem rgb(189 197 209 / 20%)",
border: "1px solid #e7eaf3",
borderRadius: "1rem",
fontSize: "16px",
fontWeight: "500",
},
input: {
padding: "0",
fontWeight: "500",
fontSize: "23px",
display: "block",
width: "100%",
},
priceSwap: {
display: "flex",
justifyContent: "space-between",
fontSize: "15px",
color: "#434343",
marginTop: "8px",
padding: "0 10px",
},
};
const nativeAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
const chainIds = {
"0x1": "eth",
"0x38": "bsc",
"0x89": "polygon",
};
function InchDexCustom({ chain, toTokenAddress, slippage }) {
const { trySwap, tokenList, getQuote } = useInchDex(chain);
console.log(tokenList)
const { Moralis, isInitialized } = useMoralis();
const { chainId } = useMoralisDapp();
const [isFromModalActive, setFromModalActive] = useState(false);
const [isToModalActive, setToModalActive] = useState(false);
const [fromToken, setFromToken] = useState();
const [toToken, setToToken] = useState();
const [fromAmount, setFromAmount] = useState();
const [quote, setQuote] = useState();
const [currentTrade, setCurrentTrade] = useState();
const { fetchTokenPrice } = useTokenPrice();
const [tokenPricesUSD, setTokenPricesUSD] = useState({});
console.log("fromToken", fromToken);
const options = { chain: chain, addresses: toTokenAddress }; //--------------------
const [ tokendata, settokendata] = useState([])
const [newslippage, setSlippage] = useState(slippage)
const fromTokenPriceUsd = useMemo(
() => (tokenPricesUSD?.[fromToken?.["address"]] ? tokenPricesUSD[fromToken?.["address"]] : null),
[tokenPricesUSD, fromToken]
);
const toTokenPriceUsd = useMemo(
() => (tokenPricesUSD?.[toToken?.["address"]] ? tokenPricesUSD[toToken?.["address"]] : null),
[tokenPricesUSD, toToken]
);
const fromTokenAmountUsd = useMemo(() => {
if (!fromTokenPriceUsd || !fromAmount) return null;
return `~$ ${(fromAmount * fromTokenPriceUsd).toFixed(4)}`;
}, [fromTokenPriceUsd, fromAmount]);
const toTokenAmountUsd = useMemo(() => {
if (!toTokenPriceUsd || !quote) return null;
return `~$ ${(Moralis.Units.FromWei(quote?.toTokenAmount, quote?.toToken?.decimals) * toTokenPriceUsd).toFixed(4)}`;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [toTokenPriceUsd, quote]);
function changeSlippage(e){
setSlippage(e.target.value);
}
// tokenPrices
useEffect(() => {
if (!isInitialized || !fromToken || !chain) return null;
fetchTokenPrice({ chain: chain, address: fromToken[["address"]] }).then((price) =>
setTokenPricesUSD({
...tokenPricesUSD,
[fromToken["address"]]: price["usdPrice"],
})
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [chain, isInitialized, fromToken]);
useEffect(() => {
if (!isInitialized || !toToken || !chain) return null;
fetchTokenPrice({ chain: chain, address: toToken[["address"]] }).then((price) =>
setTokenPricesUSD({
...tokenPricesUSD,
[toToken["address"]]: price["usdPrice"],
})
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [chain, isInitialized, toToken]);
useEffect(() => {
if (!tokenList) return null;
setFromToken(tokenList[nativeAddress]);
}, [tokenList]);
useEffect(async() => {
const result =await Moralis.Web3API.token.getTokenMetadata(options)
settokendata(result);
if(!toToken ){
setToToken(result[0]);
}
//.then(setCurrentTrade( fromToken, toTokenAddress, fromAmount, chain))
console.log(result);
if (tokendata){
}
}, [toToken]);
const ButtonState = useMemo(() => {
if (chainIds?.[chainId] !== chain) return { isActive: false, text: `Switch to ${chain}` };
// if (chainIds[chainId] !== chain)
if (!fromAmount) return { isActive: false, text: "Enter an amount" };
if (fromAmount && currentTrade) return { isActive: true, text: "Swap" };
return { isActive: false, text: "Select tokens" };
}, [fromAmount, currentTrade, chainId, chain]);
useEffect(() => {
if (fromToken && toToken && fromAmount) setCurrentTrade({ fromToken, toToken, fromAmount, chain, newslippage });
}, [toToken, fromToken, fromAmount, chain, newslippage]);
useEffect(() => {
if (currentTrade) getQuote(currentTrade).then((quote) => setQuote(quote));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentTrade]);
const PriceSwap = () => {
const Quote = quote;
if (!Quote || !tokenPricesUSD?.[toToken?.["address"]]) return null;
if (Quote?.statusCode === 400) return <>{Quote.message}</>;
console.log(Quote);
const { fromTokenAmount, toTokenAmount } = Quote;
const { symbol: fromSymbol } = fromToken;
const { symbol: toSymbol } = toToken;
const pricePerToken = parseFloat(
tokenValue(fromTokenAmount, fromToken["decimals"]) / tokenValue(toTokenAmount, toToken["decimals"])
).toFixed(6);
return (
<Text style={styles.priceSwap}>
Price:{" "}
<Text>{`1 ${toSymbol} = ${pricePerToken} ${fromSymbol} ($${tokenPricesUSD[[toToken["address"]]].toFixed(
6
)})`}</Text>
</Text>
);
};
return (
<>
<Card style={styles.card} bodyStyle={{ padding: "18px" }}>
<Card style={{ borderRadius: "1rem" }} bodyStyle={{ padding: "0.8rem" }}>
<div style={{ marginBottom: "5px", fontSize: "14px", color: "#434343" }}>From</div>
<div
style={{
display: "flex",
flexFlow: "row nowrap",
}}
>
<div>
<InputNumber
bordered={false}
placeholder="0.00"
style={{ ...styles.input, marginLeft: "-10px" }}
onChange={setFromAmount}
value={fromAmount}
/>
<Text style={{ fontWeight: "600", color: "#434343" }}>{fromTokenAmountUsd}</Text>
</div>
<Button
style={{
height: "fit-content",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderRadius: "0.6rem",
padding: "5px 10px",
fontWeight: "500",
fontSize: "17px",
gap: "7px",
border: "none",
}}
onClick={() => setFromModalActive(true)}
>
{fromToken ? (
<Image
src={fromToken?.logoURI || "https://etherscan.io/images/main/empty-token.png"}
alt="nologo"
width="30px"
preview={false}
style={{ borderRadius: "15px" }}
/>
) : (
<span>Select a token</span>
)}
<span>{fromToken?.symbol}</span>
<Arrow />
</Button>
</div>
</Card>
<div style={{ display: "flex", justifyContent: "center", padding: "10px" }}>
<ArrowDownOutlined />
</div>
<Card style={{ borderRadius: "1rem" }} bodyStyle={{ padding: "0.8rem" }}>
<div style={{ marginBottom: "5px", fontSize: "14px", color: "#434343" }}>To</div>
<div
style={{
display: "flex",
flexFlow: "row nowrap",
}}
>
<div>
<Input
bordered={false}
placeholder="0.00"
style={styles.input}
readOnly
value={quote ? Moralis.Units.FromWei(quote?.toTokenAmount, quote?.toToken?.decimals).toFixed(6) : ""}
/>
<Text style={{ fontWeight: "600", color: "#434343" }}>{toTokenAmountUsd}</Text>
</div>
<Button
style={{
height: "fit-content",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderRadius: "0.6rem",
padding: "5px 10px",
fontWeight: "500",
fontSize: "17px",
gap: "7px",
border: "none",
}}
onClick={() => setToModalActive(true)}
type={toToken ? "default" : "primary"}
>
{toToken ? (
<Image
src={toToken?.logoURI || "https://etherscan.io/images/main/empty-token.png"}
alt="nologo"
width="30px"
preview={false}
style={{ borderRadius: "15px" }}
/>
) : (
<span>Select a token</span>
)}
<span>{toToken?.symbol}</span>
<Arrow />
</Button>
</div>
</Card>
{quote && (
<div>
<Text
style={{
display: "flex",
justifyContent: "space-between",
fontSize: "15px",
color: "#434343",
marginTop: "8px",
padding: "0 10px",
}}
>
Estimated Gas: <Text>{quote?.estimatedGas}</Text>
</Text>
<PriceSwap />
</div>
)}
<div style={{ display:"flex", justifyContent:"space-between", padding:"5px 10px"}}>
<label htmlFor="">Slippage</label>
<input type="range" min="0" onChange={changeSlippage} value={newslippage} max="50" />
<input type="number" onChange={changeSlippage} value={newslippage} max="50" min="0" name="" placeholder="slippage" id="" />
</div>
<Button
type="primary"
size="large"
style={{
width: "100%",
marginTop: "15px",
borderRadius: "0.6rem",
height: "50px",
}}
onClick={() => trySwap(currentTrade)}
disabled={!ButtonState.isActive}
>
{ButtonState.text}
</Button>
</Card>
<Modal
title="Select a token"
visible={isFromModalActive}
onCancel={() => setFromModalActive(false)}
bodyStyle={{ padding: 0 }}
width="450px"
footer={null}
>
<InchModal
open={isFromModalActive}
onClose={() => setFromModalActive(false)}
setToken={setFromToken}
tokenList={tokenList}
/>
</Modal>
<Modal
title="Select a token"
visible={isToModalActive}
onCancel={() => setToModalActive(false)}
bodyStyle={{ padding: 0 }}
width="450px"
footer={null}
>
<InchModal
open={isToModalActive}
onClose={() => setToModalActive(false)}
setToken={setToToken}
tokenList={tokendata}
/>
</Modal>
</>
);
}
export default InchDexCustom;
const Arrow = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<polyline points="6 9 12 15 18 9" />
</svg>
);