integrate native coin into dex

Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
Uncle Fatso 2026-03-19 20:48:38 +03:00
parent 7be03aaa9f
commit 8d23d55ae2
Signed by: f4ts0
GPG Key ID: 565F4F2860226EBB
15 changed files with 323 additions and 105 deletions

View File

@ -1,7 +1,7 @@
{
"name": "ghost-dao-interface",
"private": true,
"version": "0.6.4",
"version": "0.6.5",
"type": "module",
"scripts": {
"dev": "vite",

View File

@ -215,7 +215,7 @@ function App() {
: <Route path="/wrapper" element={<Wrapper config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
}
<Route path="/bridge" element={<Bridge config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
<Route path="/dex/:name" element={<Dex connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
<Route path="/dex/:name" element={<Dex config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />
{isGovernanceAvailable(chainId, addressChainId) && <Route path="/governance" element={<Governance config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />}
{isGovernanceAvailable(chainId, addressChainId) && <Route path="/governance/:id" element={<ProposalDetails config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />}
{isGovernanceAvailable(chainId, addressChainId) && <Route path="/governance/create" element={<NewProposal config={config} connect={tryConnectInjected} address={address} chainId={addressChainId ? addressChainId : chainId} />} />}

View File

@ -58,6 +58,7 @@ export const TokenAllowanceGuard = ({
height = "auto",
spendAmount,
tokenName,
isNative,
owner,
spender,
decimals,
@ -88,7 +89,7 @@ export const TokenAllowanceGuard = ({
);
}
if (allowance && spendAmount && allowance.lt(spendAmount))
if (!isNative && allowance && spendAmount && allowance.lt(spendAmount))
return (
<Grid container alignItems="center">
<Grid item xs={12} sm={isVertical ? 12 : 8}>

View File

@ -16,6 +16,7 @@ import { formatCurrency, formatNumber } from "../../../helpers";
import { DecimalBigNumber } from "../../../helpers/DecimalBigNumber"
import { tokenNameConverter } from "../../../helpers/tokenConverter";
import { isNetworkLegacy } from "../../../constants";
import { EMPTY_ADDRESS } from "../../../constants/addresses";
import GhostStyledIcon from "../../Icon/GhostIcon";
import TokenStack from "../../TokenStack/TokenStack";
@ -305,7 +306,7 @@ export const Tokens = ({ address, tokens, onClose }) => {
const tokenProps = (token) => ({
...token,
expanded: expanded === token.symbol,
reserveAddress: tokens.reserve.address,
reserveAddress: EMPTY_ADDRESS,
onChangeExpanded: (e, isExpanded) => setExpanded(isExpanded ? token.symbol : null),
onAddTokenToWallet: () => addTokenToWallet(token, address),
onClose: () => onClose(),

View File

@ -1,5 +1,7 @@
import { NetworkId } from "../constants";
export const EMPTY_ADDRESS = "0x0000000000000000000000000000000000000000";
export const STAKING_ADDRESSES = {
[NetworkId.TESTNET_SEPOLIA]: "0xC2C579631Bf6daA93252154080fecfd68c6aa506",
[NetworkId.TESTNET_HOODI]: "0x25F62eDc6C89FF84E957C22336A35d2dfc861a86",

View File

@ -10,7 +10,7 @@ import {
useTheme,
} from "@mui/material";
import SettingsIcon from '@mui/icons-material/Settings';
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { useParams, useLocation, useSearchParams } from "react-router-dom";
import { Helmet } from "react-helmet";
import ReactGA from "react-ga4";
@ -28,14 +28,17 @@ import {
UNISWAP_V2_FACTORY,
RESERVE_ADDRESSES,
FTSO_ADDRESSES,
EMPTY_ADDRESS,
WETH_ADDRESSES,
} from "../../constants/addresses";
import { useTokenSymbol } from "../../hooks/tokens";
import { getTokenAddress } from "../../hooks/helpers";
import PoolContainer from "./PoolContainer";
import SwapContainer from "./SwapContainer";
import TokenModal from "./TokenModal";
const Dex = ({ chainId, address, connect }) => {
const Dex = ({ chainId, address, connect, config }) => {
const location = useLocation();
const pathname = useParams();
@ -58,11 +61,44 @@ const Dex = ({ chainId, address, connect }) => {
const [actualDestinationAddress, setActualDestinationAddress] = useState(localStorage.getItem("dex-destination"));
const [destinationAddress, setDestinationAddress] = useState(actualDestinationAddress);
const [tokenAddressTop, setTokenAddressTop] = useState(RESERVE_ADDRESSES[chainId]);
const [tokenAddressTop, setTokenAddressTop] = useState(EMPTY_ADDRESS);
const [tokenAddressBottom, setTokenAddressBottom] = useState(FTSO_ADDRESSES[chainId]);
const { symbol: tokenNameTop } = useTokenSymbol(chainId, tokenAddressTop);
const { symbol: tokenNameBottom } = useTokenSymbol(chainId, tokenAddressBottom);
const { symbol: tokenNameTopInner } = useTokenSymbol(chainId, tokenAddressTop);
const { symbol: tokenNameBottomInner } = useTokenSymbol(chainId, tokenAddressBottom);
const chainSymbol = useMemo(() => {
const chainSymbol = config?.getClient()?.chain?.nativeCurrency?.symbol;
if (chainSymbol) return chainSymbol;
return "WTF";
}, [config])
const tokenNameTop = useMemo(() => {
if (chainSymbol && tokenAddressTop === EMPTY_ADDRESS) {
return chainSymbol;
}
return tokenNameTopInner;
}, [tokenAddressTop, tokenNameTopInner, chainSymbol]);
const tokenNameBottom = useMemo(() => {
const chainSymbol = config?.getClient()?.chain?.nativeCurrency?.symbol;
if (chainSymbol && tokenAddressBottom === EMPTY_ADDRESS) {
return chainSymbol;
}
return tokenNameBottomInner;
}, [tokenAddressBottom, tokenNameBottomInner, config]);
const isWrapping = useMemo(() => {
const isNative = tokenAddressTop === EMPTY_ADDRESS;
const isWrappedNative = tokenAddressBottom === WETH_ADDRESSES[chainId];
return isNative && isWrappedNative;
}, [chainId, tokenAddressTop, tokenAddressBottom]);
const isUnwrapping = useMemo(() => {
const isWrappedNative = tokenAddressTop === WETH_ADDRESSES[chainId];
const isNative = tokenAddressBottom === EMPTY_ADDRESS;
return isNative && isWrappedNative;
}, [chainId, tokenAddressTop, tokenAddressBottom]);
useEffect(() => {
if (currentQueryParameters.has("pool")) {
@ -77,8 +113,8 @@ const Dex = ({ chainId, address, connect }) => {
setTokenAddressTop(currentQueryParameters.get("from"));
newQueryParameters.set("from", currentQueryParameters.get("from"));
} else {
setTokenAddressTop(RESERVE_ADDRESSES[chainId]);
newQueryParameters.set("from", RESERVE_ADDRESSES[chainId]);
setTokenAddressTop(EMPTY_ADDRESS);
newQueryParameters.set("from", EMPTY_ADDRESS);
}
if (currentQueryParameters.has("to")) {
@ -94,7 +130,7 @@ const Dex = ({ chainId, address, connect }) => {
useEffect(() => {
ReactGA.send({ hitType: "pageview", page: location.pathname + location.search });
}, [location])
}, [location]);
const dexAddresses = {
router: UNISWAP_V2_ROUTER[chainId],
@ -115,7 +151,7 @@ const Dex = ({ chainId, address, connect }) => {
}
const changeSwapTab = (swap) => {
if (swap) newQueryParameters.delete("pool");
if (swap || (isWrapping || isUnwrapping)) newQueryParameters.delete("pool");
else newQueryParameters.set("pool", true);
newQueryParameters.set("from", currentQueryParameters.get("from"));
newQueryParameters.set("to", currentQueryParameters.get("to"));
@ -315,6 +351,7 @@ const Dex = ({ chainId, address, connect }) => {
</Modal>
<TokenModal
chainSymbol={chainSymbol}
account={address}
chainId={chainId}
listOpen={topTokenListOpen}
@ -322,6 +359,7 @@ const Dex = ({ chainId, address, connect }) => {
setTokenAddress={setInnerTokenAddressTop}
/>
<TokenModal
chainSymbol={chainSymbol}
account={address}
chainId={chainId}
listOpen={bottomTokenListOpen}
@ -373,6 +411,8 @@ const Dex = ({ chainId, address, connect }) => {
setBottomTokenListOpen={setBottomTokenListOpen}
setIsSwap={setIsSwap}
formatDecimals={formatDecimals}
isWrapping={isWrapping}
isUnwrapping={isUnwrapping}
/>
:
<PoolContainer

View File

@ -12,7 +12,12 @@ import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { formatNumber, formatCurrency, bigIntSqrt } from "../../helpers";
import { useBalance, useTotalSupply } from "../../hooks/tokens";
import { useUniswapV2Pair, useUniswapV2PairReserves, addLiquidity } from "../../hooks/uniswapv2";
import {
useUniswapV2Pair,
useUniswapV2PairReserves,
addLiquidity,
addLiquidityETH,
} from "../../hooks/uniswapv2";
const PoolContainer = ({
tokenNameTop,
@ -27,7 +32,7 @@ const PoolContainer = ({
secondsToWait,
setTopTokenListOpen,
setBottomTokenListOpen,
formatDecimals
formatDecimals,
}) => {
const theme = useTheme();
const isSmallScreen = useMediaQuery("(max-width: 456px)");
@ -40,11 +45,13 @@ const PoolContainer = ({
balance: balanceTop,
refetch: balanceRefetchTop,
contractAddress: addressTop,
isNative: topIsNative,
} = useBalance(chainId, tokenNameTop, address);
const {
balance: balanceBottom,
refetch: balanceRefetchBottom,
contractAddress: addressBottom,
isNative: bottomIsNative,
} = useBalance(chainId, tokenNameBottom, address);
const {
@ -142,7 +149,7 @@ const PoolContainer = ({
const amountAMin = amountADesired * bigIntSlippage / one;
const amountBMin = amountBDesired * bigIntSlippage / one;
await addLiquidity(
const params = {
chainId,
tokenNameTop,
tokenNameBottom,
@ -150,9 +157,16 @@ const PoolContainer = ({
amountBDesired,
amountAMin,
amountBMin,
address,
destination,
deadline,
);
}
if (topIsNative || bottomIsNative) {
await addLiquidityETH(params)
} else {
await addLiquidity(params);
}
await balanceRefetchTop();
await balanceRefetchBottom();
@ -233,6 +247,7 @@ const PoolContainer = ({
owner={address}
spender={dexAddresses.router}
decimals={balanceTop._decimals}
isNative={topIsNative}
approvalText={"Approve " + tokenNameTop}
approvalPendingText={"Approving..."}
connect={connect}
@ -245,6 +260,7 @@ const PoolContainer = ({
owner={address}
spender={dexAddresses.router}
decimals={balanceBottom._decimals}
isNative={bottomIsNative}
approvalText={"Approve " + tokenNameBottom}
approvalPendingText={"Approving..."}
connect={connect}

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from "react";
import { useState, useMemo, useEffect } from "react";
import { Box, Typography, useTheme, useMediaQuery } from "@mui/material";
import toast from "react-hot-toast";
@ -13,8 +13,16 @@ import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { prettifySecondsInDays } from "../../helpers/timeUtil";
import { getTokenAddress } from "../../hooks/helpers";
import { useBalance } from "../../hooks/tokens";
import { useUniswapV2Pair, useUniswapV2PairReserves, swapExactTokensForTokens } from "../../hooks/uniswapv2";
import { useBalance, depositNative, withdrawWeth } from "../../hooks/tokens";
import {
useUniswapV2Pair,
useUniswapV2PairReserves,
swapExactTokensForTokens,
swapExactETHForTokens,
swapExactTokensForETH,
} from "../../hooks/uniswapv2";
import { EMPTY_ADDRESS } from "../../constants/addresses";
const SwapContainer = ({
tokenNameTop,
@ -30,7 +38,9 @@ const SwapContainer = ({
destination,
secondsToWait,
setIsSwap,
formatDecimals
formatDecimals,
isWrapping,
isUnwrapping,
}) => {
const theme = useTheme();
const isSmallScreen = useMediaQuery("(max-width: 456px)");
@ -46,12 +56,14 @@ const SwapContainer = ({
balance: balanceTop,
refetch: balanceRefetchTop,
contractAddress: addressTop,
isNative: topIsNative,
} = useBalance(chainId, tokenNameTop, address);
const {
balance: balanceBottom,
refetch: balanceRefetchBottom,
contractAddress: addressBottom,
isNative: bottomIsNative,
} = useBalance(chainId, tokenNameBottom, address);
const {
@ -75,14 +87,18 @@ const SwapContainer = ({
const setMax = () => setAmountTop(balanceTop.toString());
useEffect(() => {
if (isWrapping || isUnwrapping) {
setAmountBottom(amountTop.toString());
setNextPrice("1");
setCurrentPrice("1");
return;
}
const zero = new DecimalBigNumber(0n, 0);
const raw = new DecimalBigNumber(amountTop, balanceTop._decimals);
const amountInRaw = new DecimalBigNumber(raw._value.toBigInt(), balanceTop._decimals);
const amountInWithFee = amountInRaw.mul(new DecimalBigNumber(997n, 3));
const topAddress = getTokenAddress(chainId, tokenNameTop);
const bottomAddress = getTokenAddress(chainId, tokenNameBottom);
const amountIn = addressTop.toUpperCase() === tokenAddresses.token0.toUpperCase() ? pairReserves.reserve0 : pairReserves.reserve1;
const amountOut = addressBottom.toUpperCase() === tokenAddresses.token1.toUpperCase() ? pairReserves.reserve1 : pairReserves.reserve0;
@ -103,7 +119,15 @@ const SwapContainer = ({
setAmountBottom(amountOut.sub(newAmountOut).toString());
setNextPrice(denominator.div(newAmountOut).toString())
}
}, [amountTop, addressTop]);
}, [amountTop, addressTop, isWrapping, isUnwrapping]);
const buttonText = useMemo(() => {
let text = "Swap";
if (isWrapping) text = "Wrap";
else if (isUnwrapping) text = "Unwrap";
else if (pairAddress === EMPTY_ADDRESS) text = "Create Pool";
return text;
}, [isWrapping, isUnwrapping, pairAddress]);
const swapTokens = async () => {
setIsPending(true);
@ -120,14 +144,30 @@ const SwapContainer = ({
const amountBDesired = BigInt(Math.round(parseFloat(amountBottom) * Math.pow(10, balanceBottom._decimals)));
const amountBMin = amountBDesired * bigIntSlippage / one;
await swapExactTokensForTokens(
chainId,
amountADesired,
amountBMin,
[tokenNameTop, tokenNameBottom],
destination,
deadline
);
if (isWrapping) {
await depositNative(chainId, address, amountADesired);
} else if (isUnwrapping) {
await withdrawWeth(chainId, address, amountADesired);
} else {
const params = {
chainId,
amountADesired,
amountBMin,
tokenNameTop,
tokenNameBottom,
destination,
address,
deadline
};
if (topIsNative) {
await swapExactETHForTokens(params)
} else if (bottomIsNative) {
await swapExactTokensForETH(params)
} else {
await swapExactTokensForTokens(params);
}
}
await balanceRefetchTop();
await balanceRefetchBottom();
@ -204,6 +244,7 @@ const SwapContainer = ({
owner={address}
spender={dexAddresses.router}
decimals={balanceTop._decimals}
isNative={topIsNative}
approvalText={"Approve " + tokenNameTop}
approvalPendingText={"Approving..."}
connect={connect}
@ -223,17 +264,10 @@ const SwapContainer = ({
onClick={() => address === "" ?
connect()
:
pairAddress === "0x0000000000000000000000000000000000000000" ? setIsSwap(false) : swapTokens()
(!isWrapping && !isUnwrapping) && pairAddress === EMPTY_ADDRESS ? setIsSwap(false) : swapTokens()
}
>
{address === "" ?
"Connect"
:
pairAddress === "0x0000000000000000000000000000000000000000" ?
"Create Pool"
:
"Swap"
}
{address === "" ? "Connect" : buttonText }
</SecondaryButton>
</TokenAllowanceGuard>
</Box>

View File

@ -21,9 +21,15 @@ import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { formatNumber } from "../../helpers/";
import { useBalance, useTokenSymbol } from "../../hooks/tokens";
import { isNetworkLegacy } from "../../constants";
import { RESERVE_ADDRESSES, FTSO_ADDRESSES, STNK_ADDRESSES, GHST_ADDRESSES } from "../../constants/addresses";
import {
RESERVE_ADDRESSES,
FTSO_ADDRESSES,
STNK_ADDRESSES,
GHST_ADDRESSES,
EMPTY_ADDRESS
} from "../../constants/addresses";
const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }) => {
const TokenModal = ({ chainId, account, chainSymbol, listOpen, setListOpen, setTokenAddress }) => {
const isSmallScreen = useMediaQuery("(max-width: 599px)");
const isVerySmallScreen = useMediaQuery("(max-width: 425px)");
@ -39,6 +45,7 @@ const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }
const { symbol: searchSymbol } = useTokenSymbol(chainId, address);
const { balance: searchBalance } = useBalance(chainId, address, account);
const { balance: nativeBalance } = useBalance(chainId, chainSymbol, account);
const { balance: reserveBalance } = useBalance(chainId, "RESERVE", account);
const { balance: ftsoBalance } = useBalance(chainId, "FTSO", account);
const { balance: stnkBalance } = useBalance(chainId, "STNK", account);
@ -49,9 +56,6 @@ const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }
const { symbol: stnkSymbol } = useTokenSymbol(chainId, "STNK");
const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
const config = useConfig();
const nativeSymbol = config?.getClient()?.chain?.nativeCurrency?.symbol;
const searchToken = useMemo(() => {
return [{
name: searchSymbol,
@ -63,9 +67,15 @@ const TokenModal = ({ chainId, account, listOpen, setListOpen, setTokenAddress }
const knownTokens = useMemo(() => {
return [
{
name: chainSymbol,
icons: [chainSymbol],
balance: nativeBalance,
address: EMPTY_ADDRESS,
},
{
name: reserveSymbol,
icons: isNetworkLegacy(chainId) ? ["GDAI"] : [nativeSymbol],
icons: isNetworkLegacy(chainId) ? ["GDAI"] : [chainSymbol],
balance: reserveBalance,
address: RESERVE_ADDRESSES[chainId]
},

View File

@ -22,7 +22,7 @@ import { isNetworkLegacy } from "../../../constants";
import { useLpValuation } from "../../../hooks/treasury";
import { useTotalSupply, useTokenSymbol } from "../../../hooks/tokens";
import { RESERVE_ADDRESSES, FTSO_ADDRESSES } from "../../../constants/addresses";
import { EMPTY_ADDRESS, FTSO_ADDRESSES } from "../../../constants/addresses";
const FarmPools = ({ chainId }) => {
const isSmallScreen = useMediaQuery("(max-width: 775px)");
@ -42,7 +42,7 @@ const FarmPools = ({ chainId }) => {
tvl: reserveFtsoUniValuation,
params: createSearchParams({
pool: "true",
from: `${RESERVE_ADDRESSES[chainId]}`,
from: `${EMPTY_ADDRESS}`,
to: `${FTSO_ADDRESSES[chainId]}`,
})
},

View File

@ -1,4 +1,4 @@
export const tokenNameConverter = (chainId, name) => {
export const tokenNameConverter = (chainId, name, address) => {
if (name?.toUpperCase() === "WETH") {
switch (chainId) {
case 63:

View File

@ -142,6 +142,12 @@ export const getTokenAddress = (chainId, name) => {
case "WMETC":
address = WETH_ADDRESSES[chainId];
break;
case "ETH":
address = undefined;
break;
case "METC":
address = undefined;
break;
}
return address;
}

View File

@ -9,6 +9,7 @@ import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
import { shorten } from "../../helpers";
import { tokenNameConverter } from "../../helpers/tokenConverter";
import { config } from "../../config";
import { WETH_ADDRESSES } from "../../constants/addresses";
export const usePastVotes = (chainId, name, timepoint, address) => {
const decimals = getTokenDecimals(name);
@ -60,20 +61,29 @@ export const useTotalSupply = (chainId, name) => {
};
export const useBalance = (chainId, name, address) => {
const contractAddress = getTokenAddress(chainId, name);
const { data, refetch, error } = useInnerBalance({
let contractAddress = getTokenAddress(chainId, name);
let isNative = false;
let requestObj = {
address,
chainId,
scopeKey: `balance-${contractAddress}-${address}-${chainId}`,
token: contractAddress,
});
};
if (contractAddress !== undefined) {
requestObj.token = contractAddress;
} else {
contractAddress = WETH_ADDRESSES[chainId];
isNative = true;
}
const { data, refetch, error } = useInnerBalance(requestObj);
const balancePrepared = data ? data.value : 0n;
const decimals = data ? data.decimals : getTokenDecimals(name);
const balance = new DecimalBigNumber(balancePrepared, decimals);
return { balance, refetch, contractAddress };
return { balance, refetch, contractAddress, isNative };
}
export const useAllowance = (chainId, name, owner, spender, decimals) => {
@ -96,6 +106,7 @@ export const useAllowance = (chainId, name, owner, spender, decimals) => {
export const useTokenSymbol = (chainId, name) => {
const contractAddress = getTokenAddress(chainId, name);
const { data, refetch } = useReadContract({
abi: getTokenAbi(name),
address: contractAddress,

View File

@ -4,14 +4,12 @@ import { abi as UniswapV2Factory } from "../../abi/UniswapV2Factory.json";
import { UNISWAP_V2_FACTORY } from "../../constants/addresses";
export const useUniswapV2Pair = (chainId, factoryAddress, token0, token1) => {
const t0 = token0 > token1 ? token0 : token1;
const t1 = token0 > token1 ? token1 : token0;
const { data, refetch } = useReadContract({
abi: UniswapV2Factory,
address: factoryAddress,
functionName: "getPair",
args: [token0, token1],
scopeKey: `getPair-${t0}-${t1}-${chainId}`,
scopeKey: `getPair-${token0}-${token1}-${chainId}`,
chainId: chainId,
});

View File

@ -2,91 +2,189 @@ import { simulateContract, writeContract, waitForTransactionReceipt } from "@wag
import toast from "react-hot-toast";
import { isNetworkLegacyType } from "../../constants";
import { UNISWAP_V2_ROUTER } from "../../constants/addresses";
import { UNISWAP_V2_ROUTER, WETH_ADDRESSES } from "../../constants/addresses";
import { abi as RouterAbi } from "../../abi/UniswapV2Router.json";
import { getTokenAddress } from "../helpers";
import { config } from "../../config";
export const swapExactTokensForTokens = async (
const swapMessages = {
replacedMsg: "Swap transaction was replaced. Wait for inclusion please.",
successMsg: "Swap executed successfully! Wait for balances update.",
errorMsg: "Swap tokens failed. Check logs for error detalization.",
};
const addMessages = {
replacedMsg: "Add liquidity transaction was replaced. Wait for inclusion please.",
successMsg: "Liquidity added successfully! You should get LP tokens to your wallet.",
errorMsg: "Adding liquidity failed. Check logs for error detalization.",
};
export const swapExactETHForTokens = async ({
chainId,
amountDesired,
amountMin,
pathRaw,
amountADesired,
amountBMin,
tokenNameTop,
tokenNameBottom,
destination,
deadline
) => {
const path = pathRaw.map(tokenName => getTokenAddress(chainId, tokenName));
}) => {
const args = [
amountDesired,
amountMin,
path,
amountBMin,
[WETH_ADDRESSES[chainId], getTokenAddress(chainId, tokenNameBottom)],
destination,
deadline
];
const messages = {
replacedMsg: "Swap transaction was replaced. Wait for inclusion please.",
successMsg: "Swap executed successfully! Wait for balances update.",
errorMsg: "Swap tokens failed. Check logs for error detalization.",
};
await executeOnChainTransaction(
await executeOnChainTransaction({
chainId,
"swapExactTokensForTokens",
functionName: "swapExactETHForTokens",
args,
destination,
messages
);
account: destination,
messages: swapMessages,
value: amountADesired,
});
}
export const addLiquidity = async (
export const swapExactTokensForETH = async ({
chainId,
tokenA,
tokenB,
amountADesired,
amountBMin,
tokenNameTop,
tokenNameBottom,
destination,
address,
deadline
}) => {
const args = [
amountADesired,
amountBMin,
[getTokenAddress(chainId, tokenNameTop), WETH_ADDRESSES[chainId]],
destination,
deadline
];
await executeOnChainTransaction({
chainId,
functionName: "swapExactTokensForETH",
args,
account: address,
messages: swapMessages,
});
}
export const swapExactTokensForTokens = async ({
chainId,
amountADesired,
amountBMin,
tokenNameTop,
tokenNameBottom,
destination,
address,
deadline
}) => {
const args = [
amountADesired,
amountBMin,
[getTokenAddress(chainId, tokenNameTop), getTokenAddress(chainId, tokenNameBottom)],
destination,
deadline
];
await executeOnChainTransaction({
chainId,
functionName: "swapExactTokensForTokens",
args,
account: address,
messages: swapMessages
});
}
export const addLiquidity = async ({
chainId,
tokenNameTop,
tokenNameBottom,
amountADesired,
amountBDesired,
amountAMin,
amountBMin,
to,
address,
destination,
deadline,
) => {
const token1 = getTokenAddress(chainId, tokenA);
const token2 = getTokenAddress(chainId, tokenB);
}) => {
const args = [
token1,
token2,
getTokenAddress(chainId, tokenNameTop),
getTokenAddress(chainId, tokenNameBottom),
amountADesired,
amountBDesired,
amountAMin,
amountBMin,
to,
destination,
deadline
];
const messages = {
replacedMsg: "Add liquidity transaction was replaced. Wait for inclusion please.",
successMsg: "Liquidity added successfully! You should get LP tokens to your wallet.",
errorMsg: "Adding liquidity failed. Check logs for error detalization.",
};
await executeOnChainTransaction(
await executeOnChainTransaction({
chainId,
"addLiquidity",
functionName: "addLiquidity",
args,
to,
messages
);
account: address,
messages: addMessages
});
}
const executeOnChainTransaction = async (
export const addLiquidityETH = async ({
chainId,
tokenNameTop,
tokenNameBottom,
amountADesired,
amountBDesired,
amountAMin,
amountBMin,
address,
destination,
deadline,
}) => {
let token = getTokenAddress(chainId, tokenNameTop);
let amountTokenDesired = amountADesired;
let amountETHDesired = amountBDesired;
let amountTokenMin = amountAMin;
let amountETHMin = amountBMin;
if (token === undefined) {
token = getTokenAddress(chainId, tokenNameBottom);
amountTokenDesired = amountBDesired;
amountETHDesired = amountADesired;
amountTokenMin = amountBMin;
amountETHMin = amountAMin;
}
const args = [
token,
amountTokenDesired,
amountTokenMin,
amountETHMin,
destination,
deadline
];
await executeOnChainTransaction({
chainId,
functionName: "addLiquidityETH",
args,
account: address,
messages: addMessages,
value: amountETHDesired,
});
}
const executeOnChainTransaction = async ({
chainId,
functionName,
args,
account,
messages
) => {
messages,
value,
}) => {
try {
const { request } = await simulateContract(config, {
abi: RouterAbi,
@ -96,6 +194,7 @@ const executeOnChainTransaction = async (
account,
chainId,
type: isNetworkLegacyType(chainId) ? 'legacy' : 'eip1559',
value: value ?? 0n,
});
const txHash = await writeContract(config, request);