Skip to content

Commit 7841904

Browse files
committed
fakeUSDT contract added
1 parent 632980b commit 7841904

File tree

5 files changed

+223
-34
lines changed

5 files changed

+223
-34
lines changed

quick-starts/react-quick-start/src/App.tsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ function App() {
2828
const { userInfo } = useWeb3AuthUser();
2929
const { address } = useAccount();
3030

31-
const contractAddress = myTokenModuleMyTokenAddress[420420422];
31+
const contractAddress =
32+
myTokenModuleMyTokenAddress[
33+
420420422 as keyof typeof myTokenModuleMyTokenAddress
34+
];
3235

3336
function uiConsole(...args: any[]): void {
3437
const el = document.querySelector("#console>p");
@@ -60,16 +63,29 @@ function App() {
6063
</div>
6164
<SendTransaction />
6265
<Balance />
66+
67+
{contractAddress && (
68+
<div className="contract-section">
69+
<h3>FakeUSDT Contract Interactions</h3>
70+
<ContractData
71+
contractAddress={contractAddress}
72+
userAddresses={address ? [address] : undefined}
73+
/>
74+
</div>
75+
)}
76+
6377
<SwitchChain />
6478
<ExportPrivateKey />
6579

66-
<div className="contract-section">
67-
<h3>Contract Interactions</h3>
68-
<ContractData
69-
contractAddress={contractAddress}
70-
userAddresses={address ? [address] : undefined}
71-
/>
72-
</div>
80+
{!contractAddress && (
81+
<div className="contract-section">
82+
<h3>Contract Not Available</h3>
83+
<p>
84+
Please deploy the FakeUSDT contract and update the address in
85+
generated.ts
86+
</p>
87+
</div>
88+
)}
7389
</div>
7490
);
7591

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { fakeUsdtModuleFakeUsdtAbi } from "../generated";
2+
import {
3+
useWriteContract,
4+
useAccount,
5+
usePublicClient,
6+
useChainId,
7+
} from "wagmi";
8+
9+
import { useState } from "react";
10+
11+
export function Burn(params: {
12+
contractAddress: `0x${string}`;
13+
decimals: number;
14+
symbol: string;
15+
userBalance: bigint;
16+
}) {
17+
const { address: userAddress } = useAccount();
18+
const publicClient = usePublicClient();
19+
const chainId = useChainId();
20+
const [amount, setAmount] = useState(0);
21+
22+
const { writeContract, status, data, error } = useWriteContract();
23+
24+
const formatBalance = (balance: bigint): string => {
25+
const divisor = 10n ** BigInt(params.decimals);
26+
return (Number(balance) / Number(divisor)).toFixed(params.decimals);
27+
};
28+
29+
return (
30+
<div className="border rounded-md my-5 mx-2 p-2 w-fit inline-block">
31+
<h3 className="px-2 block mb-2 font-bold text-lg">
32+
Burn {params.symbol}s
33+
</h3>
34+
35+
<div className="px-2 mb-3 text-sm">
36+
Your balance: <span className="font-semibold">{formatBalance(params.userBalance)} {params.symbol}</span>
37+
</div>
38+
39+
<div className="text-right my-2">
40+
<label htmlFor="burnAmount" className="px-2 block mb-2 inline-block">
41+
Amount to Burn
42+
</label>
43+
<input
44+
id="burnAmount"
45+
type="number"
46+
placeholder="0"
47+
max={formatBalance(params.userBalance)}
48+
onChange={(e) => setAmount(Number(e.target.value))}
49+
disabled={status === "pending"}
50+
className="
51+
border rounded-md padding-1 pl-2 h-10 w-400
52+
focus:ring-2 focus:ring-inset focus:ring-red-600
53+
"
54+
/>
55+
</div>
56+
57+
<button
58+
onClick={async () => {
59+
if (!userAddress) return;
60+
try {
61+
const value = BigInt(amount) * 10n ** BigInt(params.decimals);
62+
63+
// Check if user has enough balance
64+
if (value > params.userBalance) {
65+
alert("Cannot burn more than your balance!");
66+
return;
67+
}
68+
69+
// Precompute gas parameters
70+
const [gasPrice, nonce, gas] = await Promise.all([
71+
publicClient?.getGasPrice().catch(() => undefined),
72+
publicClient
73+
?.getTransactionCount({ address: userAddress })
74+
.catch(() => undefined),
75+
publicClient
76+
?.estimateGas({
77+
account: userAddress,
78+
to: params.contractAddress,
79+
data: await (async () => {
80+
// Encode calldata for burn(uint256)
81+
const selector = "0x42966c68";
82+
const pad = (s: string) =>
83+
s.replace(/^0x/, "").padStart(64, "0");
84+
const calldata = selector + pad(value.toString(16));
85+
return calldata as `0x${string}`;
86+
})(),
87+
})
88+
.catch(() => undefined),
89+
]);
90+
91+
writeContract({
92+
chainId,
93+
address: params.contractAddress,
94+
abi: fakeUsdtModuleFakeUsdtAbi,
95+
functionName: "burn",
96+
args: [value],
97+
// Hint wagmi/viem for legacy by setting gasPrice
98+
...(gasPrice ? { gasPrice, type: "legacy" as const } : {}),
99+
...(gas ? { gas } : {}),
100+
...(nonce !== undefined ? { nonce } : {}),
101+
account: userAddress,
102+
});
103+
} catch (e) {
104+
console.error(e);
105+
}
106+
}}
107+
disabled={status === "pending" || amount <= 0 || params.userBalance === 0n}
108+
className="
109+
my-0 mx-3 h-10 py-0 bg-red-500 text-white rounded-md px-4
110+
focus:ring-2 focus:ring-inset focus:ring-red-600
111+
disabled:bg-gray-300 disabled:cursor-not-allowed
112+
">
113+
Burn{" "}
114+
{status === "pending"
115+
? "⏳"
116+
: status === "success"
117+
? "✅"
118+
: status === "error"
119+
? "❌"
120+
: "🔥"}
121+
</button>
122+
123+
{status === "error" && error && (
124+
<div
125+
style={{
126+
color: "red",
127+
fontSize: "14px",
128+
marginTop: "8px",
129+
padding: "8px",
130+
}}>
131+
Error: {error.message}
132+
</div>
133+
)}
134+
135+
{status === "success" && data && (
136+
<div
137+
style={{
138+
color: "green",
139+
fontSize: "14px",
140+
marginTop: "8px",
141+
padding: "8px",
142+
}}>
143+
Burn successful! Hash: {data}
144+
</div>
145+
)}
146+
147+
<div style={{ color: "gray", fontSize: "12px", marginTop: "6px" }}>
148+
🔥 You can only burn your own tokens
149+
</div>
150+
</div>
151+
);
152+
}

quick-starts/react-quick-start/src/components/ContractData.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { myTokenModuleMyTokenConfig } from "../generated";
22
import { useReadContracts } from "wagmi";
33
import { Mint } from "./Mint";
4+
import { Burn } from "./Burn";
45
import type { Abi } from "viem";
56

67
export function ContractData(params: {
@@ -119,20 +120,28 @@ export function ContractData(params: {
119120
</div>
120121
)}
121122

122-
<Mint
123-
contractAddress={params.contractAddress}
124-
ownerAddress={owner}
125-
isOwner={Boolean(isOwner)}
126-
decimals={decimals}
127-
symbol={tokenName}
128-
/>
123+
<div className="flex flex-wrap gap-4">
124+
<Mint
125+
contractAddress={params.contractAddress}
126+
ownerAddress={owner}
127+
isOwner={Boolean(isOwner)}
128+
decimals={decimals}
129+
symbol={tokenName}
130+
/>
129131

130-
{!isOwner && (
131-
<p style={{ color: "orange", fontSize: "14px", marginTop: "8px" }}>
132-
Note: You are not the contract owner. Minting may fail unless you have
133-
the MINTER_ROLE.
134-
</p>
135-
)}
132+
{params.userAddresses && params.userAddresses.length > 0 && (
133+
<Burn
134+
contractAddress={params.contractAddress}
135+
decimals={decimals}
136+
symbol={tokenName}
137+
userBalance={balances[0] || 0n}
138+
/>
139+
)}
140+
</div>
141+
142+
<p style={{ color: "green", fontSize: "14px", marginTop: "8px" }}>
143+
✅ Anyone can mint this test token! No special permissions required.
144+
</p>
136145
</>
137146
);
138147
}

quick-starts/react-quick-start/src/components/Mint.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export function Mint(params: {
113113
console.error(e);
114114
}
115115
}}
116-
disabled={status === "pending" || amount <= 0 || !params.isOwner}
116+
disabled={status === "pending" || amount <= 0}
117117
className="
118118
my-0 mx-3 h-10 py-0
119119
focus:ring-2 focus:ring-inset focus:ring-indigo-600
@@ -152,11 +152,9 @@ export function Mint(params: {
152152
</div>
153153
)}
154154

155-
{!params.isOwner && (
156-
<div style={{ color: "orange", fontSize: "12px", marginTop: "6px" }}>
157-
You are not the owner/minter. Mint may revert on-chain.
158-
</div>
159-
)}
155+
<div style={{ color: "blue", fontSize: "12px", marginTop: "6px" }}>
156+
💡 This is a test token - anyone can mint for free!
157+
</div>
160158
</div>
161159
);
162160
}

quick-starts/react-quick-start/src/generated.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2-
// MyTokenModule#MyToken
2+
// FakeUSDTModule#FakeUSDT
33
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
44

55
/**
6-
*
6+
* FakeUSDT - An upgradeable test token with USDT compatibility (6 decimals)
7+
* - Anyone can mint tokens
8+
* - Users can only burn their own tokens
9+
* - Upgradeable with UUPS pattern
710
*/
8-
export const myTokenModuleMyTokenAbi = [
11+
export const fakeUsdtModuleFakeUsdtAbi = [
912
{
1013
inputs: [],
1114
stateMutability: "nonpayable",
@@ -268,6 +271,12 @@ export const myTokenModuleMyTokenAbi = [
268271
name: "implementation",
269272
type: "address",
270273
},
274+
{
275+
indexed: true,
276+
internalType: "address",
277+
name: "newOwner",
278+
type: "address",
279+
},
271280
],
272281
name: "Upgraded",
273282
type: "event",
@@ -586,16 +595,21 @@ export const myTokenModuleMyTokenAbi = [
586595
];
587596

588597
/**
589-
*
598+
* Contract addresses for different networks
599+
* Add your deployed contract addresses here
590600
*/
591601
export const myTokenModuleMyTokenAddress = {
592602
420420422: "0x3C0A2D569531952dd5832706707cFBf097Ac9BFe",
593603
} as const;
594604

595605
/**
596-
*
606+
* Complete contract configuration for Wagmi
597607
*/
598-
export const myTokenModuleMyTokenConfig = {
608+
export const fakeUsdtModuleFakeUsdtConfig = {
599609
address: myTokenModuleMyTokenAddress,
600-
abi: myTokenModuleMyTokenAbi,
610+
abi: fakeUsdtModuleFakeUsdtAbi,
601611
} as const;
612+
613+
// Legacy exports for backward compatibility
614+
export const myTokenModuleMyTokenAbi = fakeUsdtModuleFakeUsdtAbi;
615+
export const myTokenModuleMyTokenConfig = fakeUsdtModuleFakeUsdtConfig;

0 commit comments

Comments
 (0)