Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"jose": "^6.0.11",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^6.0.0",
"tailwind-merge": "^3.2.0",
"tailwindcss": "^4.1.5",
"viem": "^2.29.0",
Expand Down
45 changes: 23 additions & 22 deletions src/components/ContractFunctions/ContractFunctions.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { multicall } from "@wagmi/core";
import { encodeFunctionData, formatEther, parseAbi } from "viem";
import { useMemo, useState } from "react";
import { encodeFunctionData, formatEther, parseAbi, parseUnits } from "viem";
import {
useAccount,
useChainId,
useConfig,
useEstimateGas,
useReadContract,
useWriteContract,
} from "wagmi";
import { useLogging } from "../../hooks/useLogging";
import {
DEFAULT_CHAIN,
MOCK_ERC20_CONTRACT,
MOCK_ERC721_CONTRACT,
} from "../../utils/constants";
import { Button } from "../common/Button";
import { useMemo, useState } from "react";

export const ContractFunctions = () => {
const { setLog } = useLogging();
Expand All @@ -27,15 +27,16 @@ export const ContractFunctions = () => {
const setLoading = (key: string, loading: boolean) => {
setLoadingStates((prev) => ({ ...prev, [key]: loading }));
};
const chainId = useChainId();

const data = useMemo(
() =>
encodeFunctionData({
abi: parseAbi(MOCK_ERC20_CONTRACT(DEFAULT_CHAIN.id).abi),
abi: parseAbi(MOCK_ERC20_CONTRACT(chainId).abi),
functionName: "transfer",
args: [address, "10"],
args: [address, parseUnits("10", 18)],
}),
[address]
[address, chainId]
);

const { refetch: refetchGasEstimate } = useEstimateGas({
Expand All @@ -49,14 +50,14 @@ export const ContractFunctions = () => {

const { writeContractAsync } = useWriteContract();
const { refetch: refetchErc20Balance } = useReadContract({
address: MOCK_ERC20_CONTRACT(DEFAULT_CHAIN.id).address,
abi: parseAbi(MOCK_ERC20_CONTRACT(DEFAULT_CHAIN.id).abi),
address: MOCK_ERC20_CONTRACT(chainId).address,
abi: parseAbi(MOCK_ERC20_CONTRACT(chainId).abi),
functionName: "balanceOf",
args: [address],
});
const { refetch: refetchErc721Balance } = useReadContract({
address: MOCK_ERC721_CONTRACT(DEFAULT_CHAIN.id).address,
abi: parseAbi(MOCK_ERC721_CONTRACT(DEFAULT_CHAIN.id).abi),
address: MOCK_ERC721_CONTRACT(chainId).address,
abi: parseAbi(MOCK_ERC721_CONTRACT(chainId).abi),
functionName: "balanceOf",
args: [address],
});
Expand All @@ -73,10 +74,10 @@ export const ContractFunctions = () => {
const mintMockTokenFn = async () => {
try {
const result = await writeContractAsync({
address: MOCK_ERC20_CONTRACT(DEFAULT_CHAIN.id).address,
abi: parseAbi(MOCK_ERC20_CONTRACT(DEFAULT_CHAIN.id).abi),
address: MOCK_ERC20_CONTRACT(chainId).address,
abi: parseAbi(MOCK_ERC20_CONTRACT(chainId).abi),
functionName: "mint",
args: [address, "10"],
args: [address, parseUnits("10", 18)],
});
setLog(`Minted token: ${result}`, "info");
} catch (error) {
Expand All @@ -87,10 +88,10 @@ export const ContractFunctions = () => {
const transferTokenFn = async () => {
try {
const result = await writeContractAsync({
address: MOCK_ERC20_CONTRACT(DEFAULT_CHAIN.id).address,
abi: parseAbi(MOCK_ERC20_CONTRACT(DEFAULT_CHAIN.id).abi),
address: MOCK_ERC20_CONTRACT(chainId).address,
abi: parseAbi(MOCK_ERC20_CONTRACT(chainId).abi),
functionName: "transfer",
args: [address, "10"],
args: [address, parseUnits("10", 18)],
});
setLog(`Transferred token: ${result}`, "info");
} catch (error) {
Expand All @@ -114,8 +115,8 @@ export const ContractFunctions = () => {
const mintMockERC721Fn = async () => {
try {
const result = await writeContractAsync({
address: MOCK_ERC721_CONTRACT(DEFAULT_CHAIN.id).address,
abi: parseAbi(MOCK_ERC721_CONTRACT(DEFAULT_CHAIN.id).abi),
address: MOCK_ERC721_CONTRACT(chainId).address,
abi: parseAbi(MOCK_ERC721_CONTRACT(chainId).abi),
functionName: "safeMint",
args: [address],
});
Expand Down Expand Up @@ -143,14 +144,14 @@ export const ContractFunctions = () => {
const result = await multicall(config, {
contracts: [
{
address: MOCK_ERC20_CONTRACT(DEFAULT_CHAIN.id).address,
abi: parseAbi(MOCK_ERC20_CONTRACT(DEFAULT_CHAIN.id).abi),
address: MOCK_ERC20_CONTRACT(chainId).address,
abi: parseAbi(MOCK_ERC20_CONTRACT(chainId).abi),
functionName: "balanceOf",
args: [address!],
},
{
address: MOCK_ERC721_CONTRACT(DEFAULT_CHAIN.id).address,
abi: parseAbi(MOCK_ERC721_CONTRACT(DEFAULT_CHAIN.id).abi),
address: MOCK_ERC721_CONTRACT(chainId).address,
abi: parseAbi(MOCK_ERC721_CONTRACT(chainId).abi),
functionName: "balanceOf",
args: [address!],
},
Expand Down
13 changes: 12 additions & 1 deletion src/components/ContractFunctions/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ErrorBoundary } from "react-error-boundary";
import { AccountFunctions } from "./AccountFunctions";
import { ContractFunctions } from "./ContractFunctions";
import { SigningFunctions } from "./SigningFunctions";
Expand All @@ -7,7 +8,17 @@ export const BlockchainFunctions = () => {
<div>
<AccountFunctions />
<SigningFunctions />
<ContractFunctions />
<ErrorBoundary
fallbackRender={({ error }) => {
return (
<div className="text-red-500 mt-4">
Blockchain Functions Error: {error?.message}
</div>
);
}}
>
<ContractFunctions />
</ErrorBoundary>
</div>
);
};
91 changes: 53 additions & 38 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { BUILD_ENV as AIRKIT_BUILD_ENV } from "@mocanetwork/airkit";
import { type Address, type Chain, defineChain } from "viem";
import { baseSepolia, soneiumMinato } from "viem/chains";
import { BUILD_ENV as AIRKIT_BUILD_ENV } from "@mocanetwork/airkit";

export const mocaTestnet: Chain & { contracts: { multicall3: { address: `0x${string}`; blockCreated: number } } } = defineChain({
export const mocaTestnet: Chain & {
contracts: { multicall3: { address: `0x${string}`; blockCreated: number } };
} = defineChain({
id: 5151,
name: "Moca Testnet",
nativeCurrency: {
Expand All @@ -28,51 +30,64 @@ export const mocaTestnet: Chain & { contracts: { multicall3: { address: `0x${str
} as const);

export const BUILD_ENV = AIRKIT_BUILD_ENV.SANDBOX;
export const DEFAULT_CHAIN = mocaTestnet;

const ERC20_ADDRESSES: { [chainId: number]: Address } = {
[baseSepolia.id]: "0xa807429271f7001ED6e5eB40e2029B7ecbA9445f",
[soneiumMinato.id]: "0x15a2e33bf32563C796b5f85e77236e20C6D1b956",
[mocaTestnet.id]: "0xF025335C838738ba426ded3ABc8Ce36B871F5c0C"
[mocaTestnet.id]: "0xF025335C838738ba426ded3ABc8Ce36B871F5c0C",
};

const ERC721_ADDRESSES: { [chainId: number]: Address } = {
[baseSepolia.id]: "0xc9061eEC6abEB13DC7815e47FFfe1b9a40A8088b",
[soneiumMinato.id]: "0x51aeA0a26D84eCa3ADE38078b6eFDa5e04702607",
[mocaTestnet.id]: "0x6c513255C62D9036aFd14dA3633C4f2e4239adD1"
[mocaTestnet.id]: "0x6c513255C62D9036aFd14dA3633C4f2e4239adD1",
};

export const MOCK_ERC20_CONTRACT = (chainId: number) => {
const erc20Address = ERC20_ADDRESSES[chainId];

if (!erc20Address) {
throw new Error(`No erc20 address found for chainId: ${chainId}`);
}

return {
address: erc20Address,
abi: [
"function balanceOf(address account) view returns (uint256)",
"function symbol() view returns (string)",
"function mint(address to, uint256 amount)",
"function transfer(address to, uint256 value)",
"error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed)",
"error ERC20InvalidSender(address sender)",
"error ERC20InvalidReceiver(address receiver)",
"error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed)",
"error ERC20InvalidApprover(address approver)",
"error ERC20InvalidSpender(address spender)",
],
};
};

export const MOCK_ERC20_CONTRACT = (chainId: number) => ({
address: ERC20_ADDRESSES[chainId],
abi: [
"function balanceOf(address account) view returns (uint256)",
"function symbol() view returns (string)",
"function mint(address to, uint256 amount)",
"function transfer(address to, uint256 value)",
"error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed)",
"error ERC20InvalidSender(address sender)",
"error ERC20InvalidReceiver(address receiver)",
"error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed)",
"error ERC20InvalidApprover(address approver)",
"error ERC20InvalidSpender(address spender)",
],
chainId: DEFAULT_CHAIN.id,
});
export const MOCK_ERC721_CONTRACT = (chainId: number) => {
const erc721Address = ERC721_ADDRESSES[chainId];

export const MOCK_ERC721_CONTRACT = (chainId: number) => ({
address: ERC721_ADDRESSES[chainId],
abi: [
"function balanceOf(address account) view returns (uint256)",
"function safeMint(address to)",
"function transferFrom(address from, address to, uint256 tokenId)",
"error ERC721InvalidOwner(address owner)",
"error ERC721NonexistentToken(uint256 tokenId)",
"error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner)",
"error ERC721InvalidSender(address sender)",
"error ERC721InvalidReceiver(address receiver)",
"error ERC721InsufficientApproval(address operator, uint256 tokenId)",
"error ERC721InvalidApprover(address approver)",
"error ERC721InvalidOperator(address operator)",
],
chainId: DEFAULT_CHAIN.id,
});
if (!erc721Address) {
throw new Error(`No erc721 address found for chainId: ${chainId}`);
}

return {
address: erc721Address,
abi: [
"function balanceOf(address account) view returns (uint256)",
"function safeMint(address to)",
"function transferFrom(address from, address to, uint256 tokenId)",
"error ERC721InvalidOwner(address owner)",
"error ERC721NonexistentToken(uint256 tokenId)",
"error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner)",
"error ERC721InvalidSender(address sender)",
"error ERC721InvalidReceiver(address receiver)",
"error ERC721InsufficientApproval(address operator, uint256 tokenId)",
"error ERC721InvalidApprover(address approver)",
"error ERC721InvalidOperator(address operator)",
],
};
};