Originally, it was a swap built on Ethereum fetching token quotes & prices via api. That version functions as intended
Now, I am working implementing conditional logic to fect the token list and data for the network that is connected to the user wallet
I did it in 2 steps:
1- Conditional logic to fetch the api string based on the connected network
import qs from "qs";
import { NextApiRequest, NextApiResponse } from "next";
import { useAccount } from "wagmi";
import { mainnet, bsc, polygon } from "../../node_modules/@wagmi/chains/dist/index";
function apiUrl(isConnected: boolean, mainnet: boolean, bsc: boolean, polygon: boolean, query: string) {
if (isConnected) {
if (mainnet) {
return `https://my.api.com//swap/v1/price?${query}`;
} else if (bsc) {
return `https://bsc.my.api.com//swap/v1/price?${query}`;
} else if (polygon) {
return `https://my.api.com//swap/v1/price?${query}`;
} else {
return `https://my.api.com//swap/v1/price?${query}`;
}
} else {
return `https://my.api.com//swap/v1/price?${query}`;
}
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<any>
) {
const { isConnected } = useAccount();
const query = qs.stringify(req.query);
const apiKey = process.env.SWAP_API_KEY;
const response = await fetch(apiUrl, {
headers: {
"0x-api-key": "MY-API-KEY",
}
});
try {
const data = await response.json();
res.json(data);
} catch (error) {
console.error(error);
res.status(500).json({ error });
}
}
2- Conditional logic to fetch the token list based on the network connected to the wallet:
import { Address } from "viem";
import { useAccount } from "wagmi";
import { mainnet, bsc, polygon } from "viem/chains";
export const MAX_ALLOWANCE =
BigInt(
115792089237316195423570985008687907853269984665640564039457584007913129639935n
);
export const exchangeProxy = "PROXY";
// type Token = {
// address: Address;
// };
interface Token {
name: string;
address: Address;
symbol: string;
decimals: number;
chainId: number;
logoURI: string;
}
// Export default array of tokens
export default function ETHEREUM_TOKENS(): Token[] {
const { isConnected } = useAccount();
return isConnected
? mainnet
? ETH_TOKENS
: bsc
? BSC_TOKENS
: polygon
? POLYGON_TOKENS
: ETH_TOKENS
: [];
}
// Export tokens by symbol
export function ETHEREUM_TOKENS_BY_SYMBOL(): Record<string, Token> {
const { isConnected } = useAccount();
return isConnected
? mainnet
? ETH_TOKENS_BY_SYMBOL
: bsc
? BSC_TOKENS_BY_SYMBOL
: polygon
? POLYGON_TOKENS_BY_SYMBOL
: ETH_TOKENS_BY_SYMBOL
: {};
}
// Export tokens by addres
export function ETHEREUM_TOKENS_BY_ADDRESS(): Record<string, Token> {
const { isConnected } = useAccount();
return isConnected
? mainnet
? ETH_TOKENS_BY_SYMBOL
: bsc
? BSC_TOKENS_BY_SYMBOL
: polygon
? POLYGON_TOKENS_BY_SYMBOL
: ETH_TOKENS_BY_SYMBOL
: {};
}
============================================================
PROBLEM:
After making the adjustements mentionned previously, my main component stopped rendering the swap box, the modal and the token lists regardless of what network is connected or not
It is not returning any errors in the browser console or the terminal
Note: It is my 1st time working entirely with typescript
============================================================
ENVIRONMENT:
- React js (ts: "5.0.4")
- Wagmi: "1.4.5"
- Viem: "^0.3.50"
- WalletConnect SDK v2
- ethers: "^6.4.0"
- web3Modal
- VsCode
============================================================
CODE BASE:
*_app.js: *
- Basic configuration
import "./../styles/globals.css";
import type { AppProps } from "next/app";
import { useEffect, useState, useRef } from "react";
import {
EthereumClient,
w3mConnectors,
w3mProvider,
} from "@web3modal/ethereum";
import { Web3Modal } from "@web3modal/react";
import { configureChains, createConfig, WagmiConfig } from "wagmi";
import SelectToken from "./components/SelectToken";
import {
mainnet,
bsc,
polygon,
} from "wagmi/chains";
require("dotenv").config();
//walletconnect
const projectId = "My_project_id";
const chains = [
mainnet,
bsc,
polygon,
];
export const publicClient: any = configureChains(chains, [
w3mProvider({ projectId }),
]);
const wagmiConfig = createConfig({
autoConnect: true,
connectors: w3mConnectors({ projectId, chains }),
publicClient,
});
const ethereumClient = new EthereumClient(wagmiConfig, chains);
export default function App({ Component, pageProps }: AppProps) {
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
return (
<div className="flex-row">
<WagmiConfig config={wagmiConfig}>
{mounted && <Component {...pageProps} />}
</WagmiConfig>
<Web3Modal projectId={projectId} ethereumClient={ethereumClient} />
</div>
);
}
index.tsx
Main component:
- Renders the swap box & token Modal
- Implement all the functionality for the swap including conditional logic to set api and token list based on connected network
- I highlighted in bold the code that is directly interacting with the components containing the conditional logic to set api and token list
//Imports
....
//Interface
interface PriceRequestParams {
sellToken: string;
buyToken: string;
buyAmount?: string;
sellAmount?: string;
takerAddress?: string;
}
//MORE CODE
.......
//FUNCTION SETTING TOKEN
export default function PriceView({
price,
setPrice,
setFinalize,
takerAddress,
}: {
price: any;
setPrice: (price: any) => void;
setFinalize: (finalize: boolean) => void;
takerAddress: Address | undefined;
}) {
// fetch price here
const [sellAmount, setSellAmount] = useState("");
const [buyAmount, setBuyAmount] = useState("");
const [tradeDirection, setTradeDirection] = useState("sell");
**const [sellToken, setSellToken] = useState("matic");**
**const [buyToken, setBuyToken] = useState("weth");**
//modal state
const [isOpen, setIsOpen] = useState(false);
const [changeToken, setChangeToken] = useState(1);
const [asset, setAsset] = useState("");
//TOKEN LISTS
**const tokens = ETHEREUM_TOKENS()**;
**const tokensBySymbol = ETHEREUM_TOKENS_BY_SYMBOL()**;
**const sellTokenDecimals = tokensBySymbol[sellToken].decimals**;
console.log(sellAmount, sellTokenDecimals, "<-");
const parsedSellAmount =
sellAmount && tradeDirection === "sell"
? parseUnits(sellAmount, sellTokenDecimals).toString()
: undefined;
**const buyTokenDecimals = tokensBySymbol[buyToken].decimals**;
const parsedBuyAmount =
buyAmount && tradeDirection === "buy"
? parseUnits(buyAmount, buyTokenDecimals).toString()
: undefined;
const { isLoading: isLoadingPrice } = useSWR(
[
"/api/price",
{
**sellToken: tokensBySymbol[sellToken].address**,
**buyToken: tokensBySymbol[buyToken].address**,
sellAmount: parsedSellAmount,
buyAmount: parsedBuyAmount,
takerAddress,
feeRecipient: FEE_RECIPIENT,
buyTokenPercentageFee: AFFILIATE_FEE,
},
],
fetcher,
{
onSuccess: (data) => {
setPrice(data);
if (tradeDirection === "sell") {
console.log(formatUnits(data.buyAmount, buyTokenDecimals), data);
setBuyAmount(formatUnits(data.buyAmount, buyTokenDecimals));
} else {
setSellAmount(formatUnits(data.sellAmount, sellTokenDecimals));
}
},
}
);
//MORE CODE
.........
** type Token = {
name: string;
address: Address;
symbol: string;
decimals: number;
chainId: number;
logoURI: string;
};**
// tokenChoice component
const TokenChoice = ({
** token: Token,**
i,
changeToken,
}: {
**token: Token;**
i: number;
changeToken: number;
}) => {
return (
<div
className={Style.tokenChoice}
key={i}
onClick={() => modifyToken(i, changeToken)}
>
<img
**src={Token.logoURI}**
**alt={Token.logoURI}**
className={Style.tokenLogo}
/>
<div className="tokenChoiceNames">
**<div className={Style.tokenName}>{Token.name}</div>**
**<div className={Style.tokenTicker}>{Token.symbol}</div>**
</div>
</div>
);
};
//MORE CODE
...........
return (
<>
{/* MODAL */}
<Modal
open={isOpen}
footer={null}
onCancel={() => setIsOpen(false)}
title="Select a token" //Modify: "select a ${network.name} token"
>
<div className={Style.modalContent}>
<input
type="text"
value={asset}
onChange={(e) => setAsset(e.target.value)}
placeholder="Search Token"
className={Style.Modal_input}
/>
<div className={Style.tokenChoiceWrapper}>
<ul>
{tokens
?.filter((token) => {
return (
token.symbol.includes(asset) ||
token.name.includes(asset) ||
token.address.includes(asset)
);
})
.map((token, i) => {
return (
<TokenChoice
key={i}
token={token}
i={i}
changeToken={changeToken}
/>
);
})}
</ul>
</div>
</div>
</Modal>
//MORE CODE
...........
{/* Token selection */}
<button
className={Style.HeroSection_box_input_button}
onClick={() => {
openModal("sellToken");
}}
>
{/* image */}
<div className={Style.HeroSection_box_input_image_container}>
<img
alt={sellToken}
className={Style.HeroSection_box_input_image}
**src={tokensBySymbol[sellToken].logoURI}**
/>
</div>
<span className={Style.HeroSection_box_input_select}>
<option value={sellToken}>
** {tokensBySymbol[sellToken].symbol}**
</option>
</span>
</button>
</section>
//MORE CODE
.........
============================================================
CONCLUSION:
Any help figuring out the issue would be much appreciated as I have not found any possible cause or solution online nor chatting with AI. Thank you!
*I attempted the following: *
1- Dozens of different syntax for setting the apis based on connected network - only the solution presented previously didn't return errors or type errors 2- Fetching the token list based on the api being used - failed 3- Fetching the token list based on the network that is connected - the solution presented above is the only one that did not return errors after a dozen of intents
I was hoping that setting both api and fetching token list based on the network conncted would allow to fetch and display the desired tokenlists both in the swap and modal but instead the browser is only returning the background gradient