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 (
-
-
- );
+
+
+ );
}
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"
- />
+ 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 (
- Redeem
+ {!needToSwitchChain
+ ? `Redeem`
+ : `Swtich to ${selectedChain?.name}`}
+
+ {needToSwitchChain && (
+
+ You will need to sign-in again,
if you need to switch
+ networks.
+
+ )}
);
}
From 6e2fb849205a24151a7d4143c9bd8f5ef7837ab1 Mon Sep 17 00:00:00 2001
From: memosys <82053242+memosys@users.noreply.github.com>
Date: Thu, 2 May 2024 20:00:47 +0530
Subject: [PATCH 4/8] updated to form approach
---
.../frontend/components/swap/Redeem.tsx | 46 +++++++++------
web-portal/frontend/components/swap/Swap.tsx | 57 +++++++++++--------
2 files changed, 64 insertions(+), 39 deletions(-)
diff --git a/web-portal/frontend/components/swap/Redeem.tsx b/web-portal/frontend/components/swap/Redeem.tsx
index 3c8db0f4..7935afb1 100644
--- a/web-portal/frontend/components/swap/Redeem.tsx
+++ b/web-portal/frontend/components/swap/Redeem.tsx
@@ -1,13 +1,18 @@
import { useState } from "react";
import { Flex, Stack, Button, TextInput, Text, Select } from "@mantine/core";
-import _, { isNumber } from "lodash";
+import _, { isNumber, isString } from "lodash";
import Image from "next/image";
import { karla } from "@frontend/utils/theme";
-
+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 } from "wagmi";
+import {
+ useChainId,
+ useWriteContract,
+ useSwitchChain,
+ useAccount,
+} from "wagmi";
import { toHex, zeroAddress } from "viem";
import { abi } from "@frontend/utils/abi";
@@ -41,14 +46,27 @@ export default function Redeem() {
const chainId = useChainId();
const { switchChain } = useSwitchChain();
+ const { address } = useAccount();
const { data: selectedTokenBalance } = useTokenBalance({
token: portrTokenData.address,
chainId: portrTokenData?.chainId,
});
- const [redeemValue, setRedeemValue] = useState(0);
- const [accountId, setAccountId] = useState();
+ const { values, getInputProps, setFieldValue } = useForm({
+ validate: {
+ accountId: (val) => isString(val),
+ redeemValue: (val: number) =>
+ val > Number(selectedTokenBalance?.formatted),
+ },
+ initialValues: {
+ accountId: "",
+ redeemValue: 0,
+ },
+ });
+
+ const { redeemValue, accountId } = values;
+
const shouldDisable =
!redeemValue ||
!(Number(selectedTokenBalance?.formatted) > 0) ||
@@ -60,10 +78,9 @@ export default function Redeem() {
};
const hexAccountId = accountId ? toHex(accountId) : zeroAddress;
- const bigNumberRedeem =
- isNumber(redeemValue) && redeemValue > 0
- ? BigInt(redeemValue * 10 ** portrTokenData?.decimals)
- : BigInt(0);
+ const bigNumberRedeem = BigInt(
+ redeemValue * 10 ** portrTokenData?.decimals ?? 0,
+ );
const handleRedeem = () =>
writeContract({
@@ -115,10 +132,7 @@ export default function Redeem() {
placeholder="Enter amount"
label="Redeem"
type="number"
- value={redeemValue}
- onChange={(e) =>
- setRedeemValue(parseFloat(e.target.value))
- }
+ {...getInputProps("redeemValue")}
styles={{
...commonStyles,
input: { ...commonStyles.input, fill: "#fff" },
@@ -169,7 +183,8 @@ export default function Redeem() {
size="sm"
style={{ fontWeight: "bold", cursor: "pointer" }}
onClick={() =>
- setRedeemValue(
+ setFieldValue(
+ "redeemValue",
Number(
_.get(
selectedTokenBalance,
@@ -203,8 +218,7 @@ export default function Redeem() {
...commonStyles,
input: { ...commonStyles.input, fill: "#fff" },
}}
- value={accountId}
- onChange={(e) => setAccountId(e.target.value)}
+ {...getInputProps("accountId")}
/>
();
- const [sellAmount, setSellAmount] = useState(0.0);
- const [buyAmount, setBuyAmount] = useState(0.0);
+
+ const { values, getInputProps, setFieldValue } = useForm({
+ validate: {
+ sellAmount: (val) =>
+ val < Number(selectedTokenBalance?.formatted)
+ ? null
+ : "Not Enough Balance",
+ buyAmount: (val: number) =>
+ isNumber(val) && val > 0 ? null : `Invalid Quote`,
+ },
+ initialValues: {
+ sellAmount: 0.0,
+ buyAmount: 0.0,
+ },
+ });
+
+ const { sellAmount, buyAmount } = values;
+
const [opened, setOpened] = useState(false);
// Data Fetching
@@ -143,18 +160,17 @@ export default function Swap() {
const handleTokenChange = (token: IToken) => {
setSelectedTokenData(token);
- setSellAmount(0.0);
- setBuyAmount(0.0);
+ setFieldValue("sellAmount", 0.0);
+ setFieldValue("buyAmount", 0.0);
};
- const handleSellAmountChange = (e: React.ChangeEvent) => {
- setSellAmount(Number(e.target.value));
+ useEffect(() => {
queryClient.refetchQueries({ queryKey: ["0xPrice"] });
queryClient.refetchQueries({ queryKey: ["0xQuote"] });
- };
+ }, [sellAmount]);
- const handleAllowance = () => {
- writeContract({
+ const handleAllowance = async () => {
+ await writeContractAsync({
chainId: selectedChainId,
address: quote?.sellTokenAddress,
abi: erc20Abi,
@@ -179,13 +195,14 @@ export default function Swap() {
useEffect(() => {
if (selectedTokenBalance?.value === BigInt(0)) {
- setBuyAmount(0.0);
+ setFieldValue("buyAmount", 0.0);
}
}, [selectedTokenBalance]);
useEffect(
() =>
- setBuyAmount(
+ setFieldValue(
+ "buyAmount",
Number(quote?.buyAmount) / 10 ** portrTokenData?.decimals,
),
[quote],
@@ -234,8 +251,7 @@ export default function Swap() {
placeholder="Enter amount"
label="Swap"
type="number"
- value={sellAmount}
- onChange={(e) => handleSellAmountChange(e)}
+ {...getInputProps("sellAmount")}
styles={{
...commonStyles,
input: { ...commonStyles.input, fill: "#fff" },
@@ -301,12 +317,12 @@ export default function Swap() {
size="sm"
style={{ fontWeight: "bold", cursor: "pointer" }}
onClick={() =>
- setSellAmount(
+ setFieldValue(
+ "sellAmount",
Number(
_.get(
selectedTokenBalance,
"formatted",
- 0,
),
),
)
@@ -334,17 +350,12 @@ export default function Swap() {
...commonStyles,
input: { ...commonStyles.input, fill: "#fff" },
}}
- value={
- !isQuoteLoading && !isQuoteFetching && buyAmount
- ? buyAmount
- : ""
- }
leftSection={
isQuoteLoading || isQuoteFetching ? (
) : null
}
- onChange={(e) => setBuyAmount(parseFloat(e.target.value))}
+ {...getInputProps("buyAmount")}
readOnly
/>