From 000a6957fb848963ca7a2ecdccb99bc68f49142a Mon Sep 17 00:00:00 2001 From: memosys <82053242+memosys@users.noreply.github.com> Date: Thu, 2 May 2024 18:35:49 +0530 Subject: [PATCH 1/8] save --- .../frontend/components/swap/Redeem.tsx | 337 +++++---- web-portal/frontend/components/swap/Swap.tsx | 660 +++++++++-------- web-portal/frontend/package.json | 103 +-- web-portal/frontend/utils/abi.ts | 678 ++++++++++++++++++ 4 files changed, 1267 insertions(+), 511 deletions(-) create mode 100644 web-portal/frontend/utils/abi.ts diff --git a/web-portal/frontend/components/swap/Redeem.tsx b/web-portal/frontend/components/swap/Redeem.tsx index 1ba61b51..932cfa2b 100644 --- a/web-portal/frontend/components/swap/Redeem.tsx +++ b/web-portal/frontend/components/swap/Redeem.tsx @@ -7,165 +7,212 @@ import { karla } from "@frontend/utils/theme"; import { portrTokenData } from "@frontend/utils/consts"; import { chains } from "@frontend/utils/Web3Provider"; import { useTokenBalance } from "@frontend/utils/hooks"; +import { useChainId, useWriteContract } from "wagmi"; +import web3 from 'web3'; + +import { abi } from "@frontend/utils/abi"; // Common styles for TextInput and Select components const commonStyles = { - input: { - outline: "none", - border: "none", - background: "none", - fontSize: 24, - }, - label: { - color: "#000", - marginLeft: 10, - }, + input: { + outline: "none", + border: "none", + background: "none", + fontSize: 24, + }, + label: { + color: "#000", + marginLeft: 10, + }, }; const chainOptions = _.map(chains, "name").filter( - (c) => !c.includes("Ethereum"), + (c) => !c.includes("Ethereum"), ); export default function Redeem() { - const [selectedChainId, setSelectedChainId] = useState(10); + const [selectedChainId, setSelectedChainId] = useState(10); + const { writeContract } = useWriteContract(); - const { data: selectedTokenBalance } = useTokenBalance({ - token: portrTokenData.address, - chainId: portrTokenData?.chainId, - }); + const chainId = useChainId(); + const { data: selectedTokenBalance } = useTokenBalance({ + token: portrTokenData.address, + chainId: portrTokenData?.chainId, + }); - const [redeemValue, setRedeemValue] = useState(0); + const [redeemValue, setRedeemValue] = useState(0); + const [accountId, setAccountId] = useState(); + const shouldDisable = + !redeemValue || + !(Number(selectedTokenBalance?.formatted) > 0) || + !accountId || + chainId !== selectedChainId; - return ( - - { + const selectedChain = _.find( + chains, + (c) => _.toLower(c.name) === _.toLower(val as string), + ); + setSelectedChainId(selectedChain?.id as number); + }} + label="Select Network" + /> + + + + + setRedeemValue(parseFloat(e.target.value)) + } + styles={{ + ...commonStyles, + input: { ...commonStyles.input, fill: "#fff" }, + error: { marginLeft: 10 }, + }} + error={ + redeemValue > + Number(_.get(selectedTokenBalance, "formatted")) + ? "Not enough balance" + : undefined + } + /> + + + + + + + {`$` + + (isNaN(redeemValue) ? 0 : redeemValue * 5).toFixed( + 6, + )} + + + + {Number( + _.get(selectedTokenBalance, "formatted") ?? 0, + ).toFixed(6)} + - - setRedeemValue( - _.get(selectedTokenBalance, "formatted", 0) as number, - ) - } + + setRedeemValue( + Number( + _.get( + selectedTokenBalance, + "formatted", + 0, + ), + ), + ) + } + > + max + + + + + - max - - - - - - - - - - + setAccountId(e.target.value)} + /> + + + + - - - ); + + + ); } diff --git a/web-portal/frontend/components/swap/Swap.tsx b/web-portal/frontend/components/swap/Swap.tsx index 98b38d15..0f980500 100644 --- a/web-portal/frontend/components/swap/Swap.tsx +++ b/web-portal/frontend/components/swap/Swap.tsx @@ -1,16 +1,16 @@ import { useEffect, useState } from "react"; import { - Flex, - Stack, - Button, - TextInput, - Text, - Select, - Loader, + Flex, + Stack, + Button, + TextInput, + Text, + Select, + Loader, } from "@mantine/core"; import _ from "lodash"; import Image from "next/image"; -import { crimson, karla } from "@frontend/utils/theme"; +import { karla } from "@frontend/utils/theme"; import { IToken } from "@frontend/utils/types"; import { SearchableSelectModal } from "./SearchableSelectModal"; import { Address, erc20Abi } from "viem"; @@ -18,350 +18,380 @@ import { supportedChains } from "@frontend/utils/consts"; import { chains } from "@frontend/utils/Web3Provider"; import { - useCheckAllowance, - useQuote, - useTokenBalance, - useTokenList, - useTokenPrice, + useCheckAllowance, + useQuote, + useTokenBalance, + useTokenList, + useTokenPrice, } from "@frontend/utils/hooks"; import { portrTokenData } from "@frontend/utils/consts"; import { useQueryClient } from "@tanstack/react-query"; import { - useChainId, - useSendTransaction, - useSwitchChain, - useWriteContract, + useChainId, + useSendTransaction, + useSwitchChain, + useWriteContract, } from "wagmi"; // Common styles for TextInput and Select components const commonStyles = { - input: { - outline: "none", - border: "none", - background: "none", - fontSize: 24, - }, - label: { - color: "#000", - marginLeft: 10, - }, + input: { + outline: "none", + border: "none", + background: "none", + fontSize: 24, + }, + label: { + color: "#000", + marginLeft: 10, + }, }; const chainOptions = _.map(chains, "name").filter((c) => !c.includes("Eth")); export default function Swap() { - // Network/Token data - const [selectedChainId, setSelectedChainId] = useState(10); - const selectedChain = _.find( - chains, - (c) => Number(c.id) === Number(selectedChainId), - ); - const { data: tokenList } = useTokenList({ chainId: selectedChainId }); - const defaultToken = _.first(tokenList) as IToken; + // Network/Token data + const [selectedChainId, setSelectedChainId] = useState(10); + const selectedChain = _.find( + chains, + (c) => Number(c.id) === Number(selectedChainId), + ); + const { data: tokenList } = useTokenList({ chainId: selectedChainId }); + const defaultToken = _.first(tokenList) as IToken; - const exchangeProxy = _.get( - _.find(supportedChains, { id: selectedChainId }), - "exchangeProxy", - ) as unknown as Address; + const exchangeProxy = _.get( + _.find(supportedChains, { id: selectedChainId }), + "exchangeProxy", + ) as unknown as Address; - // Utils - const chainId = useChainId(); - const { switchChain } = useSwitchChain(); - const { writeContract } = useWriteContract(); - const { sendTransaction } = useSendTransaction(); - const queryClient = useQueryClient(); + // Utils + const chainId = useChainId(); + const { switchChain } = useSwitchChain(); + const { writeContract } = useWriteContract(); + const { sendTransaction } = useSendTransaction(); + const queryClient = useQueryClient(); - // UI States - const [selectedTokenData, setSelectedTokenData] = useState(); - const [sellAmount, setSellAmount] = useState(0.0); - const [buyAmount, setBuyAmount] = useState(0.0); - const [opened, setOpened] = useState(false); + // UI States + const [selectedTokenData, setSelectedTokenData] = useState(); + const [sellAmount, setSellAmount] = useState(0.0); + const [buyAmount, setBuyAmount] = useState(0.0); + const [opened, setOpened] = useState(false); - // Data Fetching - const { data: selectedTokenBalance } = useTokenBalance({ - token: - selectedTokenData?.address === defaultToken?.address - ? undefined - : selectedTokenData?.address!, - chainId: selectedTokenData?.chainId!, - }); + // Data Fetching + const { data: selectedTokenBalance } = useTokenBalance({ + token: + selectedTokenData?.address === defaultToken?.address + ? undefined + : selectedTokenData?.address!, + chainId: selectedTokenData?.chainId!, + }); - const { data: selectedTokenPrice } = useTokenPrice({ - token: selectedTokenData?.address!, - chainId: selectedTokenData?.chainId!, - }); + const { data: selectedTokenPrice } = useTokenPrice({ + token: selectedTokenData?.address!, + chainId: selectedTokenData?.chainId!, + }); - const { - data: quote, - isLoading: isQuoteLoading, - isFetching: isQuoteFetching, - } = useQuote({ - sellToken: selectedTokenData?.address!, - chainId: selectedTokenData?.chainId!, - sellAmount: Number(sellAmount * 10 ** selectedTokenData?.decimals!), - }); + const { + data: quote, + isLoading: isQuoteLoading, + isFetching: isQuoteFetching, + } = useQuote({ + sellToken: selectedTokenData?.address!, + chainId: selectedTokenData?.chainId!, + sellAmount: Number(sellAmount * 10 ** selectedTokenData?.decimals!), + }); - const { data: allowance } = useCheckAllowance({ - sellTokenAddress: selectedTokenData?.address!, - selectedChainId, - exchangeProxy, - }); + const { data: allowance } = useCheckAllowance({ + sellTokenAddress: selectedTokenData?.address!, + selectedChainId, + exchangeProxy, + }); - // Helpers - const showError = - sellAmount > Number(_.get(selectedTokenBalance, "formatted")) || - !selectedTokenBalance; + // Helpers + const showError = + sellAmount > Number(_.get(selectedTokenBalance, "formatted")) || + !selectedTokenBalance; - const shouldDisable = - isQuoteLoading || - isQuoteFetching || - !buyAmount || - !sellAmount || - showError || - !quote || - !selectedChain || - !selectedTokenData || - !selectedTokenBalance; + const shouldDisable = + isQuoteLoading || + isQuoteFetching || + !buyAmount || + !sellAmount || + showError || + !quote || + !selectedChain || + !selectedTokenData || + !selectedTokenBalance; - const sellAmountBigNumber = Number.isNaN(sellAmount) - ? BigInt(0) - : BigInt(sellAmount * 10 ** (selectedTokenData?.decimals ?? 18)); + const sellAmountBigNumber = Number.isNaN(sellAmount) + ? BigInt(0) + : BigInt(sellAmount * 10 ** (selectedTokenData?.decimals ?? 18)); - const needToSwitchChain = chainId !== selectedChainId; - const needToApproveToken = - allowance === BigInt(0) || - (allowance && - allowance < BigInt(sellAmount * 10 ** selectedTokenData?.decimals!)); + const needToSwitchChain = chainId !== selectedChainId; + const needToApproveToken = + allowance === BigInt(0) || + (allowance && + allowance < + BigInt(sellAmount * 10 ** selectedTokenData?.decimals!)); - // Action Handlers - const handleSwitchNetwork = () => { - if (chainId !== quote?.chainId) { - switchChain({ chainId: quote?.chainId }); - } - }; + // Action Handlers + const handleSwitchNetwork = () => { + if (chainId !== quote?.chainId) { + switchChain({ chainId: quote?.chainId }); + } + }; - const handleTokenChange = (token: IToken) => { - setSelectedTokenData(token); - setSellAmount(0.0); - setBuyAmount(0.0); - }; + const handleTokenChange = (token: IToken) => { + setSelectedTokenData(token); + setSellAmount(0.0); + setBuyAmount(0.0); + }; - const handleSellAmountChange = (e: React.ChangeEvent) => { - setSellAmount(Number(e.target.value)); - queryClient.refetchQueries({ queryKey: ["0xPrice"] }); - queryClient.refetchQueries({ queryKey: ["0xQuote"] }); - }; + const handleSellAmountChange = (e: React.ChangeEvent) => { + setSellAmount(Number(e.target.value)); + queryClient.refetchQueries({ queryKey: ["0xPrice"] }); + queryClient.refetchQueries({ queryKey: ["0xQuote"] }); + }; - const handleAllowance = () => { - writeContract({ - chainId: selectedChainId, - address: quote?.sellTokenAddress, - abi: erc20Abi, - functionName: "approve", - args: [exchangeProxy, sellAmountBigNumber], - }); - }; + const handleAllowance = () => { + writeContract({ + chainId: selectedChainId, + address: quote?.sellTokenAddress, + abi: erc20Abi, + functionName: "approve", + args: [exchangeProxy, sellAmountBigNumber], + }); + }; - const handleSwap = () => { - sendTransaction({ - to: quote?.to!, - value: quote?.value, - data: quote?.data, - }); - }; + const handleSwap = () => { + sendTransaction({ + to: quote?.to!, + value: quote?.value, + data: quote?.data, + }); + }; - // Effects + // Effects - useEffect(() => { - if (!selectedTokenData) setSelectedTokenData(defaultToken); - }, [defaultToken]); + useEffect(() => { + if (!selectedTokenData) setSelectedTokenData(defaultToken); + }, [defaultToken]); - useEffect(() => { - if (selectedTokenBalance?.value === BigInt(0)) { - setBuyAmount(0.0); - } - }, [selectedTokenBalance]); + useEffect(() => { + if (selectedTokenBalance?.value === BigInt(0)) { + setBuyAmount(0.0); + } + }, [selectedTokenBalance]); - useEffect( - () => - setBuyAmount(Number(quote?.buyAmount) / 10 ** portrTokenData?.decimals), - [quote], - ); + useEffect( + () => + setBuyAmount( + Number(quote?.buyAmount) / 10 ** portrTokenData?.decimals, + ), + [quote], + ); - return ( - - setOpened(false)} - opened={opened} - options={tokenList!} - onSelect={(token: IToken) => { - handleTokenChange(token); - setOpened(false); - }} - /> - { + const selectedChain = _.find( + chains, + (c) => _.toLower(c.name) === _.toLower(val as string), + ); + setSelectedChainId(selectedChain?.id as number); + }} + label="Select Network" + /> - - - handleSellAmountChange(e)} - styles={{ - ...commonStyles, - input: { ...commonStyles.input, fill: "#fff" }, - error: { marginLeft: 10 }, - }} - error={showError ? "Not enough balance" : undefined} - /> - - - - - - - {`$ `} - {( - Number(sellAmount ?? 0) * - Number( - _.get(selectedTokenPrice, [selectedTokenData?.address!], 0), - ) || 0.0 - ).toFixed(6)} - + + + handleSellAmountChange(e)} + styles={{ + ...commonStyles, + input: { ...commonStyles.input, fill: "#fff" }, + error: { marginLeft: 10 }, + }} + error={showError ? "Not enough balance" : undefined} + /> + + + + + + + {`$ `} + {( + Number(sellAmount ?? 0) * + Number( + _.get( + selectedTokenPrice, + [selectedTokenData?.address!], + 0, + ), + ) || 0.0 + ).toFixed(6)} + - - - {Number(_.get(selectedTokenBalance, "formatted") ?? 0).toFixed(6)} - + + + {Number( + _.get(selectedTokenBalance, "formatted") ?? 0, + ).toFixed(6)} + - - setSellAmount( - _.get(selectedTokenBalance, "formatted", 0) as number, - ) - } + + setSellAmount( + Number( + _.get( + selectedTokenBalance, + "formatted", + 0, + ), + ), + ) + } + > + max + + + + + - max - - - - - - : null - } - onChange={(e) => setBuyAmount(parseFloat(e.target.value))} - readOnly - /> - - + + ) : null + } + onChange={(e) => setBuyAmount(parseFloat(e.target.value))} + readOnly + /> + + - - {needToSwitchChain && ( - - You will need to sign-in again,
if you need to switch networks. -
- )} -
- ); + + {needToSwitchChain && ( + + You will need to sign-in again,
if you need to switch + networks. +
+ )} + + ); } diff --git a/web-portal/frontend/package.json b/web-portal/frontend/package.json index 3301abbb..aa1ce593 100644 --- a/web-portal/frontend/package.json +++ b/web-portal/frontend/package.json @@ -1,53 +1,54 @@ { - "name": "frontend", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev --port=3000", - "build": "next build", - "start": "next start --port=3000", - "lint": "next lint" - }, - "dependencies": { - "@mantine/charts": "^7.7.1", - "@mantine/core": "^7.7.1", - "@mantine/dates": "^7.7.1", - "@mantine/form": "^7.7.1", - "@mantine/hooks": "^7.7.1", - "@mantine/modals": "^7.7.1", - "@mantine/notifications": "^7.7.1", - "@mantine/nprogress": "^7.7.1", - "@mantine/spotlight": "^7.7.1", - "@tabler/icons-react": "^2.47.0", - "@tanstack/react-query": "^5.28.6", - "@types/js-cookie": "^3.0.6", - "@web3modal/siwe": "^4.1.1", - "@web3modal/wagmi": "^4.1.1", - "dayjs": "^1.11.10", - "encoding": "^0.1.13", - "iron-session": "^8.0.1", - "jotai": "^2.7.1", - "js-cookie": "^3.0.5", - "lodash": "^4.17.21", - "next": "14.1", - "react": "^18", - "react-dom": "^18", - "recharts": "2", - "sharp": "^0.33.2", - "siwe": "^2.1.4", - "viem": "^2.8.18", - "wagmi": "^2.5.12" - }, - "devDependencies": { - "@types/lodash": "^4.17.0", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "eslint": "^8", - "eslint-config-next": "14.0.4", - "postcss": "^8.4.33", - "postcss-preset-mantine": "^1.12.3", - "postcss-simple-vars": "^7.0.1", - "typescript": "^5" - } + "name": "frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --port=3000", + "build": "next build", + "start": "next start --port=3000", + "lint": "next lint" + }, + "dependencies": { + "@mantine/charts": "^7.7.1", + "@mantine/core": "^7.7.1", + "@mantine/dates": "^7.7.1", + "@mantine/form": "^7.7.1", + "@mantine/hooks": "^7.7.1", + "@mantine/modals": "^7.7.1", + "@mantine/notifications": "^7.7.1", + "@mantine/nprogress": "^7.7.1", + "@mantine/spotlight": "^7.7.1", + "@tabler/icons-react": "^2.47.0", + "@tanstack/react-query": "^5.28.6", + "@web3modal/siwe": "^4.1.1", + "@web3modal/wagmi": "^4.1.1", + "dayjs": "^1.11.10", + "encoding": "^0.1.13", + "iron-session": "^8.0.1", + "jotai": "^2.7.1", + "js-cookie": "^3.0.5", + "lodash": "^4.17.21", + "next": "14.1", + "react": "^18", + "react-dom": "^18", + "recharts": "2", + "sharp": "^0.33.2", + "siwe": "^2.1.4", + "viem": "^2.8.18", + "wagmi": "^2.5.12", + "web3": "^4.8.0" + }, + "devDependencies": { + "@types/lodash": "^4.17.0", + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "@types/js-cookie": "^3.0.6", + "eslint": "^8", + "eslint-config-next": "14.0.4", + "postcss": "^8.4.33", + "postcss-preset-mantine": "^1.12.3", + "postcss-simple-vars": "^7.0.1", + "typescript": "^5" + } } diff --git a/web-portal/frontend/utils/abi.ts b/web-portal/frontend/utils/abi.ts new file mode 100644 index 00000000..cd3c6d94 --- /dev/null +++ b/web-portal/frontend/utils/abi.ts @@ -0,0 +1,678 @@ +export const abi = [ + { + inputs: [], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [ + { + internalType: "address", + name: "target", + type: "address", + }, + ], + name: "AddressEmptyCode", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "AddressInsufficientBalance", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "allowance", + type: "uint256", + }, + { + internalType: "uint256", + name: "needed", + type: "uint256", + }, + ], + name: "ERC20InsufficientAllowance", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address", + }, + { + internalType: "uint256", + name: "balance", + type: "uint256", + }, + { + internalType: "uint256", + name: "needed", + type: "uint256", + }, + ], + name: "ERC20InsufficientBalance", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "approver", + type: "address", + }, + ], + name: "ERC20InvalidApprover", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "receiver", + type: "address", + }, + ], + name: "ERC20InvalidReceiver", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "ERC20InvalidSender", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + ], + name: "ERC20InvalidSpender", + type: "error", + }, + { + inputs: [], + name: "EnforcedPause", + type: "error", + }, + { + inputs: [], + name: "ExpectedPause", + type: "error", + }, + { + inputs: [], + name: "FailedInnerCall", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "OwnableInvalidOwner", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "OwnableUnauthorizedAccount", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "SafeERC20FailedOperation", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "bytes32", + name: "_identifier", + type: "bytes32", + }, + { + indexed: false, + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + ], + name: "Applied", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "_oldDataFeed", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "_newDataFeed", + type: "address", + }, + ], + name: "DataFeedSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "_oldPrice", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "_newPrice", + type: "uint256", + }, + ], + name: "PriceSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "from", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Unpaused", + type: "event", + }, + { + inputs: [ + { + internalType: "address", + name: "_to", + type: "address", + }, + { + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + ], + name: "adminMint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "spender", + type: "address", + }, + ], + name: "allowance", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "_identifier", + type: "bytes32", + }, + { + internalType: "uint256", + name: "_amount", + type: "uint256", + }, + ], + name: "applyToAccount", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "approve", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "balanceOf", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "dataFeed", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [ + { + internalType: "uint8", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "mint", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "price", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_price", + type: "uint256", + }, + ], + name: "setPrice", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_feed", + type: "address", + }, + { + internalType: "uint256", + name: "_price", + type: "uint256", + }, + ], + name: "setPriceAndFeed", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address payable", + name: "_to", + type: "address", + }, + ], + name: "sweep", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_erc20", + type: "address", + }, + { + internalType: "address", + name: "_to", + type: "address", + }, + ], + name: "sweepToken", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "transfer", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "from", + type: "address", + }, + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "transferFrom", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "unpause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +]; From 360601e3ede9d1b1099581db15554bc8cfe84220 Mon Sep 17 00:00:00 2001 From: memosys <82053242+memosys@users.noreply.github.com> Date: Thu, 2 May 2024 18:41:52 +0530 Subject: [PATCH 2/8] save --- web-portal/backend/src/utils/utils.service.ts | 7 +++---- web-portal/frontend/components/swap/Redeem.tsx | 4 ++-- web-portal/frontend/package.json | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/web-portal/backend/src/utils/utils.service.ts b/web-portal/backend/src/utils/utils.service.ts index 56d49d62..e89549a1 100644 --- a/web-portal/backend/src/utils/utils.service.ts +++ b/web-portal/backend/src/utils/utils.service.ts @@ -2,9 +2,9 @@ import { Injectable, Inject, HttpException, HttpStatus } from '@nestjs/common'; import { CustomPrismaService } from 'nestjs-prisma'; import { PrismaClient, TransactionType } from '@/.generated/client'; import { Cron, CronExpression } from '@nestjs/schedule'; -import { Log, parseAbiItem } from 'viem'; +import { Log, parseAbiItem, fromHex } from 'viem'; import { viemClient } from './viemClient'; -import web3 from 'web3'; + interface IParsedLog { tenantId: string; @@ -151,8 +151,7 @@ export class UtilsService { }); const parsedLogs: IParsedLog[] = logs.map((log: any) => ({ - tenantId: web3.utils - .toAscii(log?.args?._identifier!) + tenantId: fromHex(log?.args?._identifier!, 'string') .replaceAll(`\x00`, ''), amount: Number(log?.args?._amount!), referenceId: log.transactionHash!, diff --git a/web-portal/frontend/components/swap/Redeem.tsx b/web-portal/frontend/components/swap/Redeem.tsx index 932cfa2b..ec64a574 100644 --- a/web-portal/frontend/components/swap/Redeem.tsx +++ b/web-portal/frontend/components/swap/Redeem.tsx @@ -8,7 +8,7 @@ import { portrTokenData } from "@frontend/utils/consts"; import { chains } from "@frontend/utils/Web3Provider"; import { useTokenBalance } from "@frontend/utils/hooks"; import { useChainId, useWriteContract } from "wagmi"; -import web3 from 'web3'; +import { toHex } from "viem"; import { abi } from "@frontend/utils/abi"; @@ -54,7 +54,7 @@ export default function Redeem() { address: portrTokenData?.address, abi, functionName: "applyToAccount", - args: [web.utils.], + args: [toHex(accountId!), BigInt(redeemValue * 10 ** 18)], }); return ( diff --git a/web-portal/frontend/package.json b/web-portal/frontend/package.json index aa1ce593..e6b39306 100644 --- a/web-portal/frontend/package.json +++ b/web-portal/frontend/package.json @@ -35,8 +35,7 @@ "sharp": "^0.33.2", "siwe": "^2.1.4", "viem": "^2.8.18", - "wagmi": "^2.5.12", - "web3": "^4.8.0" + "wagmi": "^2.5.12" }, "devDependencies": { "@types/lodash": "^4.17.0", From f3135303c032729d6cb2db02b027af3ee056c2f4 Mon Sep 17 00:00:00 2001 From: memosys <82053242+memosys@users.noreply.github.com> Date: Thu, 2 May 2024 19:23:01 +0530 Subject: [PATCH 3/8] save --- .../frontend/components/swap/Redeem.tsx | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/web-portal/frontend/components/swap/Redeem.tsx b/web-portal/frontend/components/swap/Redeem.tsx index ec64a574..3c8db0f4 100644 --- a/web-portal/frontend/components/swap/Redeem.tsx +++ b/web-portal/frontend/components/swap/Redeem.tsx @@ -1,14 +1,14 @@ import { useState } from "react"; import { Flex, Stack, Button, TextInput, Text, Select } from "@mantine/core"; -import _ from "lodash"; +import _, { isNumber } from "lodash"; import Image from "next/image"; import { karla } from "@frontend/utils/theme"; import { portrTokenData } from "@frontend/utils/consts"; import { chains } from "@frontend/utils/Web3Provider"; import { useTokenBalance } from "@frontend/utils/hooks"; -import { useChainId, useWriteContract } from "wagmi"; -import { toHex } from "viem"; +import { useChainId, useWriteContract, useSwitchChain } from "wagmi"; +import { toHex, zeroAddress } from "viem"; import { abi } from "@frontend/utils/abi"; @@ -32,9 +32,16 @@ const chainOptions = _.map(chains, "name").filter( export default function Redeem() { const [selectedChainId, setSelectedChainId] = useState(10); + const selectedChain = _.find( + chains, + (c) => Number(c.id) === Number(selectedChainId), + ); + const { writeContract } = useWriteContract(); const chainId = useChainId(); + const { switchChain } = useSwitchChain(); + const { data: selectedTokenBalance } = useTokenBalance({ token: portrTokenData.address, chainId: portrTokenData?.chainId, @@ -45,8 +52,18 @@ export default function Redeem() { const shouldDisable = !redeemValue || !(Number(selectedTokenBalance?.formatted) > 0) || - !accountId || - chainId !== selectedChainId; + !accountId; + const needToSwitchChain = chainId !== selectedChainId; + + const handleSwitchNetwork = () => { + switchChain({ chainId: selectedChainId }); + }; + + const hexAccountId = accountId ? toHex(accountId) : zeroAddress; + const bigNumberRedeem = + isNumber(redeemValue) && redeemValue > 0 + ? BigInt(redeemValue * 10 ** portrTokenData?.decimals) + : BigInt(0); const handleRedeem = () => writeContract({ @@ -54,9 +71,16 @@ export default function Redeem() { address: portrTokenData?.address, abi, functionName: "applyToAccount", - args: [toHex(accountId!), BigInt(redeemValue * 10 ** 18)], + args: [hexAccountId, bigNumberRedeem], }); + console.log({ + handleRedeem, + writeContract, + hexAccountId, + bigNumberRedeem, + }); + return ( {!needToSwitchChain ? `Redeem` From bfac06e915ad3a2f8df9646e56a0b09e1743cda1 Mon Sep 17 00:00:00 2001 From: memosys <82053242+memosys@users.noreply.github.com> Date: Thu, 2 May 2024 20:21:21 +0530 Subject: [PATCH 7/8] better --- web-portal/frontend/components/swap/Redeem.tsx | 9 +++++---- web-portal/frontend/components/swap/Swap.tsx | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/web-portal/frontend/components/swap/Redeem.tsx b/web-portal/frontend/components/swap/Redeem.tsx index 97a3675a..e42dbe6f 100644 --- a/web-portal/frontend/components/swap/Redeem.tsx +++ b/web-portal/frontend/components/swap/Redeem.tsx @@ -56,7 +56,7 @@ export default function Redeem() { validate: { accountId: (val) => isString(val), redeemValue: (val: number) => - val > Number(selectedTokenBalance?.formatted), + val > Number(_.get(selectedTokenBalance, "formatted", 0)), }, initialValues: { accountId: "", @@ -68,7 +68,7 @@ export default function Redeem() { const shouldDisable = !redeemValue || - !(Number(selectedTokenBalance?.formatted) > 0) || + !(Number(_.get(selectedTokenBalance, "formatted", 0)) > 0) || !accountId; const needToSwitchChain = chainId !== selectedChainId; @@ -101,6 +101,7 @@ export default function Redeem() { data, isPending, isSuccess, + selectedTokenBalance, }); return ( @@ -145,7 +146,7 @@ export default function Redeem() { }} error={ redeemValue > - Number(_.get(selectedTokenBalance, "formatted")) + Number(_.get(selectedTokenBalance, "formatted", 0)) ? "Not enough balance" : undefined } @@ -179,7 +180,7 @@ export default function Redeem() { {Number( - _.get(selectedTokenBalance, "formatted") ?? 0, + _.get(selectedTokenBalance, "formatted", 0), ).toFixed(6)} diff --git a/web-portal/frontend/components/swap/Swap.tsx b/web-portal/frontend/components/swap/Swap.tsx index ae36d4b3..d9014429 100644 --- a/web-portal/frontend/components/swap/Swap.tsx +++ b/web-portal/frontend/components/swap/Swap.tsx @@ -78,7 +78,7 @@ export default function Swap() { const { values, getInputProps, setFieldValue } = useForm({ validate: { sellAmount: (val) => - val < Number(selectedTokenBalance?.formatted) + val < Number(_.get(selectedTokenBalance, "formatted", 0)) ? null : "Not Enough Balance", buyAmount: (val: number) => @@ -126,7 +126,7 @@ export default function Swap() { // Helpers const showError = - sellAmount > Number(_.get(selectedTokenBalance, "formatted")) || + sellAmount > Number(_.get(selectedTokenBalance, "formatted", 0)) || !selectedTokenBalance; const shouldDisable = @@ -309,7 +309,7 @@ export default function Swap() { {Number( - _.get(selectedTokenBalance, "formatted") ?? 0, + _.get(selectedTokenBalance, "formatted", 0), ).toFixed(6)} @@ -324,6 +324,7 @@ export default function Swap() { _.get( selectedTokenBalance, "formatted", + 0, ), ), ) From 85aa008bf8c6e6f26d8f71186849125c2b916c63 Mon Sep 17 00:00:00 2001 From: memosys <82053242+memosys@users.noreply.github.com> Date: Thu, 2 May 2024 20:32:14 +0530 Subject: [PATCH 8/8] everything works! --- .../frontend/components/swap/Redeem.tsx | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/web-portal/frontend/components/swap/Redeem.tsx b/web-portal/frontend/components/swap/Redeem.tsx index e42dbe6f..d12e51a2 100644 --- a/web-portal/frontend/components/swap/Redeem.tsx +++ b/web-portal/frontend/components/swap/Redeem.tsx @@ -7,12 +7,7 @@ import { useForm } from "@mantine/form"; import { portrTokenData } from "@frontend/utils/consts"; import { chains } from "@frontend/utils/Web3Provider"; import { useTokenBalance } from "@frontend/utils/hooks"; -import { - useChainId, - useWriteContract, - useSwitchChain, - useAccount, -} from "wagmi"; +import { useChainId, useWriteContract, useSwitchChain } from "wagmi"; import { toHex, zeroAddress } from "viem"; import { abi } from "@frontend/utils/abi"; @@ -42,7 +37,7 @@ export default function Redeem() { (c) => Number(c.id) === Number(selectedChainId), ); - const { writeContract, data, isPending, isSuccess } = useWriteContract(); + const { writeContractAsync } = useWriteContract(); const chainId = useChainId(); const { switchChain } = useSwitchChain(); @@ -76,13 +71,18 @@ export default function Redeem() { switchChain({ chainId: selectedChainId }); }; - const hexAccountId = accountId ? toHex(accountId) : zeroAddress; + const hexAccountId = accountId + ? toHex(accountId, { + size: 32, + }) + : zeroAddress; const bigNumberRedeem = BigInt( redeemValue * 10 ** portrTokenData?.decimals ?? 0, ); - const handleRedeem = () => - writeContract({ + const handleRedeem = async () => { + console.log("Attempting to redeem..."); + await writeContractAsync({ abi, chainId: selectedChainId, address: portrTokenData?.address, @@ -90,20 +90,16 @@ export default function Redeem() { args: [hexAccountId, bigNumberRedeem], }); + console.log("Attempt was made"); + }; + console.log({ handleRedeem, - writeContract, + writeContractAsync, hexAccountId, bigNumberRedeem, }); - console.log({ - data, - isPending, - isSuccess, - selectedTokenBalance, - }); - return (