荒唐的NFT(三) - 前端调用合约

预览地址
源码地址

核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import { useEffect, useState, useMemo } from "react";
import { useSelector, useDispatch } from "react-redux";
import InputNumber from "rc-input-number";
// 用于选择链接你的钱包,移动H5可用, 增加非钱包打开网页的链接钱包体验
import { useConnectModal, useAccount } from "@web3modal/react";
// etherjs.Web3Provider
import { Web3Provider } from "@ethersproject/providers";
// etherjs.Contract
import { Contract } from "@ethersproject/contracts";
// etherjs.Units
import {
parseEther,
formatEther,
formatUnits,
parseUnits,
} from "@ethersproject/units";
import { BigNumber } from "@ethersproject/bignumber";
import { setErrorMsg } from "@/store/modules/app";

// 合约 ABI
import json from "@/assets/WorldCupRabbitNFT.json";

import "animate.css";
import "rc-input-number/assets/index.css";

import type { RootState } from "@/store";

const contract_address: string = process.env.REACT_APP_CONTRACT_ADDRESS || "";
// 获取你metamask中的provider
const provider = window.ethereum
? new Web3Provider(window.ethereum)
: undefined;
// 链接合约ABI
let contract = new Contract(contract_address, json.abi, provider);

// 与合约保持一致
const price = 0.041;
const max = 400;
const successInfo = { msg: "", hash: "" };

const Mint = () => {
const errorMsg = useSelector((state: RootState) => state.app.errorMsg);
const dispatch = useDispatch();

const { open } = useConnectModal();
const { account } = useAccount();

const [paused, setPaused] = useState(false);
const [lastCount, setLastCount] = useState(400);
const [commonGas, setCommonGas] = useState("0");
const [count, setCount] = useState(1);
const [move, setMove] = useState(false);
const [successMsg, setSuccessMsg] = useState({ ...successInfo });

// 获取 与钱包交互的mint信息
const getMintTxParams = async () => {
const data = await contract.populateTransaction.mint(count);
// const nonce = await contract.signer.getTransactionCount()
return {
...data,
// nonce,
value: parseEther(totalPrice),
};
};

const getCommonGas = async () => {
const params = await getMintTxParams();
try {
// 估算gas费
const bigNumberGas = await contract.signer.estimateGas(params);
const gas = formatUnits(bigNumberGas, "gwei");
setCommonGas(gas);
} catch (err: any) {
if (err.reason.includes("paused")) {
return setPaused(true);
}
dispatch(setErrorMsg(err.reason));
console.dir(err);
}
};
// 总价显示
const totalPrice = useMemo(() => {
if (account.isConnected) {
setTimeout(() => {
getCommonGas();
}, 100);
}
const _c = BigNumber.from(count);

const _p = parseUnits(`${price}`);

return formatEther(_c.mul(_p));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [count, account.isConnected]);

// 获取合约中没被mint的nft
const getLastCount = async () => {
const bigNum = await contract.totalSupply();
setLastCount(max - bigNum.toNumber());
};

const mint = async () => {
if (!contract.signer) {
return open();
}
setSuccessMsg({ ...successInfo });
setMove(true);

try {
// 获取交易参数
const params = await getMintTxParams();
// 唤起 metamask,同意交易则执行 resolve
const tx = await contract.signer.sendTransaction(params);
// 等待交易完成
const done = await tx.wait();

if (done.transactionHash) {
setSuccessMsg({
msg: `Ok! You can see it in your wallet later, or you can check`,
hash: done.transactionHash,
});
getLastCount();
}
setMove(false);
} catch (error: any) {
const { action, reason } = error;
console.dir(error);
// JSON.stringify(error)
const msg = reason
? `${action}: ${reason}`
: "An error has occurred. You need to try resetting your account or re importing";

dispatch(setErrorMsg(msg));
setMove(false);
}
};

const handleChange = (nextValue: number | null) => {
setCount(nextValue || count);
};

useEffect(() => {
if (account.address && provider) {
const signer = provider.getSigner(account.address);
contract = contract.connect(signer);
getLastCount();
}
}, [account.address]);

return (
<>
<div className="flex-1 mt-10 sm:mt-32 heng-bg bg-auto sm:bg-contain sm:bg-bottom">
<div className="text-center m-auto p-8 bg-white shadow-xl rounded-lg w-11/12 sm:w-9/12 relative">
{paused ? (
<>Sorry, We Paused There</>
) : lastCount === 0 ? (
<>Sorry, We Soldout</>
) : (
<>
<div className="m-4 p-4 bg-indigo-500 text-white font-bold rounded-lg">
We decided that each wallet can have 10 tokens
</div>
<div className="static sm:absolute connect-font">
You maybe need {totalPrice} + {commonGas} ETH
</div>
<div className="static sm:absolute right-8 font-bold connect-font">
Last {lastCount}/400
</div>
<div className="p-4 pt-10 mb-4">
<InputNumber
className="!text-lg !h-10"
min={1}
max={lastCount}
precision={0}
onChange={handleChange}
value={count}
/>
</div>
<button
className={`mint-font text-3xl sm:text-5xl animate__animated ${
move ? "animate__tada" : ""
}`}
onClick={mint}
disabled={move}
>
Mint {count === 1 ? "A" : count} Rabbit{count === 1 ? "" : "s"}{" "}
!
</button>
{!move && (
<div className="mt-8">
<span className="error-font text-xl break-words">
{errorMsg}
</span>
</div>
)}
{move && (
<div className="mt-8">
<span className="green-font text-xl">
We are mitting, please Wait ...
</span>
</div>
)}
{successMsg.hash && (
<div className="mt-8 break-words">
<span className="green-font text-xl">
{successMsg.msg} on{" "}
<a
className="active-font"
href={`https://etherscan.io/tx/${successMsg.hash}`}
>
etherscan
</a>
</span>
<p>{successMsg.hash}</p>
</div>
)}
</>
)}
</div>
</div>
</>
);
};

export default Mint;

荒唐的NFT(三) - 前端调用合约

http://example.com/2023/03/04/教程/荒唐的NFT-调用合约/

作者

Huasun47

发布于

2023-03-04

更新于

2023-03-04

许可协议