Files
han 6702feefe4
Some checks failed
Lint / ci (lts/*, ubuntu-latest) (push) Has been cancelled
feat: finish challenge
2026-01-21 11:14:11 +07:00

188 lines
7.2 KiB
TypeScript

"use client";
import { useState } from "react";
import { AddressInput } from "@scaffold-ui/components";
import { IntegerInput } from "@scaffold-ui/debug-contracts";
import { useWatchBalance } from "@scaffold-ui/hooks";
import type { NextPage } from "next";
import { formatEther } from "viem";
import { useAccount } from "wagmi";
import { useDeployedContractInfo, useScaffoldReadContract, useScaffoldWriteContract } from "~~/hooks/scaffold-eth";
import { getTokenPrice, multiplyTo1e18 } from "~~/utils/scaffold-eth/priceInWei";
const TokenVendor: NextPage = () => {
const [toAddress, setToAddress] = useState("");
const [tokensToSend, setTokensToSend] = useState("");
const [tokensToBuy, setTokensToBuy] = useState<string | bigint>("");
const [isApproved, setIsApproved] = useState(false);
const [tokensToSell, setTokensToSell] = useState<string>("");
const { address } = useAccount();
const { data: yourTokenSymbol } = useScaffoldReadContract({
contractName: "YourToken",
functionName: "symbol",
});
const { data: yourTokenBalance } = useScaffoldReadContract({
contractName: "YourToken",
functionName: "balanceOf",
args: [address],
});
const { data: vendorContractData } = useDeployedContractInfo({ contractName: "Vendor" });
const { writeContractAsync: writeVendorAsync } = useScaffoldWriteContract({ contractName: "Vendor" });
const { writeContractAsync: writeYourTokenAsync } = useScaffoldWriteContract({ contractName: "YourToken" });
const { data: vendorTokenBalance } = useScaffoldReadContract({
contractName: "YourToken",
functionName: "balanceOf",
args: [vendorContractData?.address],
});
const { data: vendorEthBalance } = useWatchBalance({ address: vendorContractData?.address });
const { data: tokensPerEth } = useScaffoldReadContract({
contractName: "Vendor",
functionName: "tokensPerEth",
});
return (
<>
<div className="flex items-center flex-col flex-grow pt-10">
<div className="flex flex-col items-center bg-base-100 shadow-lg shadow-secondary border-8 border-secondary rounded-xl p-6 mt-24 w-full max-w-lg">
<div className="text-xl">
Your token balance:{" "}
<div className="inline-flex items-center justify-center">
{parseFloat(formatEther(yourTokenBalance || 0n)).toFixed(4)}
<span className="font-bold ml-1">{yourTokenSymbol}</span>
</div>
</div>
<hr className="w-full border-secondary my-3" />
<div>
Vendor token balance:{" "}
<div className="inline-flex items-center justify-center">
{Number(formatEther(vendorTokenBalance || 0n)).toFixed(4)}
<span className="font-bold ml-1">{yourTokenSymbol}</span>
</div>
</div>
<div>
Vendor eth balance: {Number(formatEther(vendorEthBalance?.value || 0n)).toFixed(4)}
<span className="font-bold ml-1">ETH</span>
</div>
</div>
<div className="flex flex-col items-center space-y-4 bg-base-100 shadow-lg shadow-secondary border-8 border-secondary rounded-xl p-6 mt-8 w-full max-w-lg">
<div className="text-xl">Buy tokens</div>
<div>{tokensPerEth?.toString() || 0} tokens per ETH</div>
<div className="w-full flex flex-col space-y-2">
<IntegerInput
placeholder="amount of tokens to buy"
value={tokensToBuy.toString()}
onChange={value => setTokensToBuy(value)}
disableMultiplyBy1e18
/>
</div>
<button
className="btn btn-secondary mt-2"
onClick={async () => {
try {
await writeVendorAsync({ functionName: "buyTokens", value: getTokenPrice(tokensToBuy, tokensPerEth) });
} catch (err) {
console.error("Error calling buyTokens function", err);
}
}}
>
Buy Tokens
</button>
</div>
{!!yourTokenBalance && (
<div className="flex flex-col items-center space-y-4 bg-base-100 shadow-lg shadow-secondary border-8 border-secondary rounded-xl p-6 mt-8 w-full max-w-lg">
<div className="text-xl">Transfer tokens</div>
<div className="w-full flex flex-col space-y-2">
<AddressInput placeholder="to address" value={toAddress} onChange={value => setToAddress(value)} />
<IntegerInput
placeholder="amount of tokens to send"
value={tokensToSend}
onChange={value => setTokensToSend(value as string)}
disableMultiplyBy1e18
/>
</div>
<button
className="btn btn-secondary"
onClick={async () => {
try {
await writeYourTokenAsync({
functionName: "transfer",
args: [toAddress, multiplyTo1e18(tokensToSend)],
});
} catch (err) {
console.error("Error calling transfer function", err);
}
}}
>
Send Tokens
</button>
</div>
)}
{/* Sell Tokens */}
{!!yourTokenBalance && (
<div className="flex flex-col items-center space-y-4 bg-base-100 shadow-lg shadow-secondary border-8 border-secondary rounded-xl p-6 mt-8 w-full max-w-lg">
<div className="text-xl">Sell tokens</div>
<div>{tokensPerEth?.toString() || 0} tokens per ETH</div>
<div className="w-full flex flex-col space-y-2">
<IntegerInput
placeholder="amount of tokens to sell"
value={tokensToSell}
onChange={value => setTokensToSell(value as string)}
disabled={isApproved}
disableMultiplyBy1e18
/>
</div>
<div className="flex gap-4">
<button
className={`btn ${isApproved ? "btn-disabled" : "btn-secondary"}`}
onClick={async () => {
try {
await writeYourTokenAsync({
functionName: "approve",
args: [vendorContractData?.address, multiplyTo1e18(tokensToSell)],
});
setIsApproved(true);
} catch (err) {
console.error("Error calling approve function", err);
}
}}
>
Approve Tokens
</button>
<button
className={`btn ${isApproved ? "btn-secondary" : "btn-disabled"}`}
onClick={async () => {
try {
await writeVendorAsync({ functionName: "sellTokens", args: [multiplyTo1e18(tokensToSell)] });
setIsApproved(false);
} catch (err) {
console.error("Error calling sellTokens function", err);
}
}}
>
Sell Tokens
</button>
</div>
</div>
)}
</div>
</>
);
};
export default TokenVendor;