Skip to content

Commit

Permalink
send tx implementation
Browse files Browse the repository at this point in the history
0xharsha committed Oct 20, 2023
1 parent f51d49f commit f1009f3
Showing 3 changed files with 275 additions and 12 deletions.
3 changes: 2 additions & 1 deletion pages/index.tsx
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ import { BaseGoerli } from "../utils/chain/baseGoerli";
import { useWagmi } from "../utils/wagmi/WagmiContext";
import Login from "../ui_components/login/Login";
import { usePathname } from "next/navigation";
import { SendTx } from "../ui_components/home/Send";

export type THandleStep = {
handleSteps: (step: number) => void;
@@ -224,7 +225,7 @@ export default function Home() {
case ESTEPS.TWO:
return <ConnectWallet signIn={signIn} handleSteps={handleSteps} loader={loader} />;
case ESTEPS.THREE:
return <HomePage />;
return <SendTx provider={provider} />;
default:
return <></>;
}
13 changes: 2 additions & 11 deletions ui_components/SecondaryBtn.tsx
Original file line number Diff line number Diff line change
@@ -14,19 +14,10 @@ interface ISecondaryBtn {
}

export default function SecondaryBtn(props: ISecondaryBtn) {
const {
title,
onClick,
rightImage,
leftImage,
showShareIcon,
className,
btnDisable,
loading,
} = props;
const { title, onClick, rightImage, leftImage, showShareIcon, className, btnDisable, loading } = props;
return (
<button
className={`py-4 text-white support_text_bold rounded-lg flex gap-1 items-center w-full justify-center border border-white max-w-[400px] mx-auto ${className}`}
className={`py-4 support_text_bold rounded-lg flex gap-1 items-center w-full justify-center border max-w-[400px] mx-auto ${className}`}
disabled={btnDisable}
onClick={onClick}
>
271 changes: 271 additions & 0 deletions ui_components/home/Send.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
import "react-toastify/dist/ReactToastify.css";
import { initWasm } from "@trustwallet/wallet-core";
import { serializeError } from "eth-rpc-errors";
import { BigNumber, ethers } from "ethers";
import Lottie from "lottie-react";
import Image from "next/image";
import { useRouter } from "next/router";
import { FC, useContext, useEffect, useState } from "react";
import { toast } from "react-toastify";
import { ToastContainer } from "react-toastify";
import { parseEther } from "viem";

import { getBalance, getRelayTransactionStatus, getSendTransactionStatus, getUsdPrice } from "../../apiServices";
import { GlobalContext } from "../../context/GlobalContext";
import { LOGGED_IN, THandleStep } from "../../pages";
import * as loaderAnimation from "../../public/lottie/loader.json";
import { getCurrencyFormattedNumber, getTokenFormattedNumber, getTokenValueFormatted, hexToNumber } from "../../utils";
import { BaseGoerli } from "../../utils/chain/baseGoerli";
import { icons } from "../../utils/images";
import { Wallet } from "../../utils/wallet";
import PrimaryBtn from "../PrimaryBtn";
import SecondaryBtn from "../SecondaryBtn";
import { useWagmi } from "../../utils/wagmi/WagmiContext";
import ReactTyped from "react-typed";
import { createSafe } from "@instadapp/avocado";

export interface ILoadChestComponent {
provider?: any;
}
export const SendTx: FC<ILoadChestComponent> = (props) => {
const { provider } = props;

const {
state: { loggedInVia, address },
} = useContext(GlobalContext);

const router = useRouter();

const [value, setValue] = useState("");
const [price, setPrice] = useState("");
const [inputValue, setInputValue] = useState("");
const [tokenPrice, setTokenPrice] = useState("");
const [tokenValue, setTokenValue] = useState(0);
const [fromAddress, setFromAddress] = useState("");
const [loading, setLoading] = useState(false);
const [transactionLoading, setTransactionLoading] = useState(false);
const [open, setOpen] = useState(false);
const [toggle, setToggle] = useState(true);
const [btnDisable, setBtnDisable] = useState(true);
const [balanceInUsd, setBalanceInUsd] = useState("");
const [showActivity, setShowActivity] = useState(false);
const [chestLoadingText, setChestLoadingText] = useState("");
const [toAddress, setToAddress] = useState("");

const handleToggle = () => {
setToggle(!toggle);
};

const { sendTransaction } = useWagmi();

useEffect(() => {
if (address) {
fetchBalance();
}
}, [address]);

const fetchBalance = async () => {
setLoading(true);
getUsdPrice()
.then(async (res: any) => {
setTokenPrice(res.data.ethereum.usd);
setFromAddress(address);
const balance = (await getBalance(address)) as any;
setTokenValue(getTokenFormattedNumber(hexToNumber(balance.result) as unknown as string, 18));
const formatBal = ((hexToNumber(balance.result) / Math.pow(10, 18)) * res.data.ethereum.usd).toFixed(3);
setPrice(getCurrencyFormattedNumber(formatBal));
setBalanceInUsd(formatBal);
setLoading(false);
})
.catch((e) => {
console.log(e);
});
};

const handleValueClick = (val: string) => {
setValue(`$${val}`);
const valueWithoutDollarSign = val.replace(/[^\d.]/g, "");
const tokenIputValue = Number(valueWithoutDollarSign) / Number(tokenPrice);
setInputValue(getTokenValueFormatted(Number(tokenIputValue)));
};

const handleInputChange = (val: string) => {
const valueWithoutDollarSign = val.replace(/[^\d.]/g, "");
let appendDollar = "";
if (Number(valueWithoutDollarSign) > 0) {
appendDollar = "$";
}
setValue(`${appendDollar}${valueWithoutDollarSign}`);
const tokenIputValue = Number(valueWithoutDollarSign) / Number(tokenPrice);
setInputValue(getTokenValueFormatted(Number(tokenIputValue)));
if (Number(valueWithoutDollarSign) < Number(balanceInUsd)) {
setBtnDisable(false);
} else {
setBtnDisable(true);
}
};

const createWallet = async () => {
const _inputValue = inputValue.replace(/[^\d.]/g, "");
if (_inputValue) {
const bgVal = BigNumber.from(parseEther(inputValue));
const ethProvider = new ethers.providers.Web3Provider(provider);
const safe = createSafe(ethProvider.getSigner());
const res = await safe.sendTransaction({
to: toAddress,
value: bgVal,
chainId: Number(BaseGoerli.chainId),
});
console.log("Res", res);
}
};

return (
<div className="pt-[156px] bg-white h-[100dvh] relative">
<div className="container mx-auto relative">
{!transactionLoading ? (
<div>
{!showActivity ? (
<>
<div className="rounded-lg border border-secondary-100 ">
<div className="flex items-center justify-between py-2 px-4">
<div>
<p className="text-secondary-100 paragraph">YOUR BALANCE</p>
<div className="flex items-start gap-3 my-2">
<Image
src={icons.helpIcon}
alt="transferIcon"
onClick={handleToggle}
className="cursor-pointer"
/>
{toggle ? (
loading ? (
<div className="w-full h-full">
<div className="w-[40px] h-[10px] bg-white/10 animate-pulse rounded-lg mb-2"></div>
<div className="w[40px] h-[10px] bg-white/10 animate-pulse rounded-lg "></div>
</div>
) : (
<div>
<p className="text-secondary-100 text-[24px] font-semibold leading-10 mb-2">{price}</p>
<p className="text-secondary-100 text-[12px] leading-[14px]">{tokenValue} ETH</p>
</div>
)
) : loading ? (
<div className="w-full h-full">
<div className="w-[40px] h-[10px] bg-white/10 animate-pulse rounded-lg mb-2"></div>
<div className="w[40px] h-[10px] bg-white/10 animate-pulse rounded-lg "></div>
</div>
) : (
<div>
<p className="text-secondary-100 text-[24px] font-semibold leading-10 mb-2">
~ {tokenValue} ETH
</p>
<p className="text-secondary-100 text-[12px] leading-[14px]">{price}</p>
</div>
)}
</div>
</div>
<div className="flex items-center gap-2">
<Image src={icons.ethLogo} alt="transferIcon" />
<p className="text-secondary-100 text-[24px] font-normal leading-9">ETH</p>
</div>
</div>
</div>
<div className="w-full mt-5 ">
<div className="relative rounded-lg border border-secondary-100 h-auto p-4">
<div className="flex items-center justify-center">
<div>
<div className="flex items-center justify-center">
{/* <p className="text-[32px] text-white">$</p> */}
<input
name="usdValue"
style={{ caretColor: "white" }}
inputMode="decimal"
type="text"
className={`dollorInput pl-0 pt-2 pb-1 backdrop-blur-xl text-[32px] border-none text-center bg-transparent text-secondary-100 placeholder-grey rounded-lg block w-full focus:outline-none focus:ring-transparent`}
placeholder="$0"
value={value}
onChange={(e) => {
handleInputChange(e.target.value);
}}
disabled={loading}
onWheel={() => (document.activeElement as HTMLElement).blur()}
/>
</div>
{Number(inputValue) > 0 && (
<p className="text-secondary text-[12px] leading-[14px] text-center">~ {inputValue} ETH</p>
)}
</div>
</div>
</div>
</div>
<div className="grid grid-cols-3 gap-3 mt-5">
<div
className="rounded-lg border border-gray-500 bg-white/5 p-2 cursor-pointer"
role="presentation"
onClick={() => {
handleValueClick("10");
}}
>
<p className="text-center text-secondary-100">$10</p>
</div>
<div
className="rounded-lg border border-gray-500 bg-white/5 p-2 cursor-pointer"
role="presentation"
onClick={() => {
handleValueClick("20");
}}
>
<p className="text-center text-secondary-100">$20</p>
</div>
<div
className="rounded-lg border border-gray-500 bg-white/5 p-2 cursor-pointer"
role="presentation"
onClick={() => {
handleValueClick("50");
}}
>
<p className="text-center text-secondary-100">$50</p>
</div>
</div>
<div className="mt-5">
<input
type="text"
id="first_name"
className="border border-secondary-100 text-gray-900 text-sm rounded-lg block w-full p-3"
placeholder="Enter to wallet address"
value={toAddress}
onChange={(e) => {
setToAddress(e.target.value);
}}
/>
</div>
<div className="relative mt-10">
<div className={`${!btnDisable && value ? "opacity-100" : "opacity-50"} flex gap-2 justify-center`}>
<SecondaryBtn
className={`w-[100%] border-secondary-100 mx-0 ${
btnDisable || !value ? "cursor-not-allowed" : ""
}`}
title={"Send"}
onClick={createWallet}
/>
</div>
</div>
</>
) : null}
</div>
) : (
<div className="w-[full] max-w-[600px] h-full relative flex flex-col text-center items-center gap-5 mx-auto mt-20">
<ReactTyped
className="text-secondary-100 text-[24px]"
strings={[chestLoadingText]}
typeSpeed={40}
loop={true}
/>
<Lottie animationData={loaderAnimation} />
</div>
)}
</div>
</div>
);
};

0 comments on commit f1009f3

Please sign in to comment.