├── .codesandbox
└── workspace.json
├── .gitignore
├── README.md
├── index.html
├── package.json
├── postcss.config.js
├── src
├── App.jsx
├── XEN.js
├── XenWitch.js
├── components
│ ├── Card.jsx
│ └── MintedList.jsx
├── helper.js
├── index.jsx
├── store.js
└── styles.css
├── tailwind.config.js
├── vite.config.ts
└── yarn.lock
/.codesandbox/workspace.json:
--------------------------------------------------------------------------------
1 | {
2 | "responsive-preview": {
3 | "Mobile": [
4 | 320,
5 | 675
6 | ],
7 | "Tablet": [
8 | 1024,
9 | 765
10 | ],
11 | "Desktop": [
12 | 1400,
13 | 800
14 | ],
15 | "Desktop HD": [
16 | 1920,
17 | 1080
18 | ]
19 | }
20 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # xen-witch-frontend
2 | Created with CodeSandbox
3 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
23 | Xen Tool By BoxMrChen
24 |
25 |
26 |
27 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xen-witch",
3 | "version": "1.0.0",
4 | "description": "",
5 | "keywords": [],
6 | "main": "src/index.js",
7 | "dependencies": {
8 | "@rainbow-me/rainbowkit": "0.7.1",
9 | "@sentry/react": "^7.14.2",
10 | "@sentry/tracing": "^7.14.2",
11 | "add": "^2.0.6",
12 | "daisyui": "^2.31.0",
13 | "ethers": "5.7.1",
14 | "react": "18.2.0",
15 | "react-dom": "18.2.0",
16 | "react-hot-toast": "^2.4.0",
17 | "react-scripts": "4.0.0",
18 | "recoil": "^0.7.5",
19 | "wagmi": "0.6.8",
20 | "yarn": "^1.22.19"
21 | },
22 | "devDependencies": {
23 | "@babel/runtime": "7.13.8",
24 | "@vitejs/plugin-react-refresh": "^1.3.6",
25 | "autoprefixer": "^10.4.12",
26 | "postcss": "^8.4.17",
27 | "tailwindcss": "^3.1.8",
28 | "typescript": "4.1.3",
29 | "vite": "^3.1.7"
30 | },
31 | "scripts": {
32 | "start": "vite",
33 | "build": "vite build"
34 | },
35 | "browserslist": [
36 | ">0.2%",
37 | "not dead",
38 | "not ie <= 11",
39 | "not op_mini all"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { ConnectButton, darkTheme, getDefaultWallets, RainbowKitProvider } from "@rainbow-me/rainbowkit";
2 | import "@rainbow-me/rainbowkit/styles.css";
3 | import * as Sentry from "@sentry/react";
4 | import { BrowserTracing } from "@sentry/tracing";
5 | import { ethers } from "ethers";
6 | import React, { useEffect, useMemo, useState } from 'react';
7 | import toast, { Toaster } from "react-hot-toast";
8 | import { RecoilRoot, useRecoilState } from "recoil";
9 | import {
10 | chain,
11 | configureChains,
12 | createClient,
13 | useAccount,
14 | useContractRead, useContractWrite,
15 | useProvider,
16 | useSigner,
17 | WagmiConfig
18 | } from "wagmi";
19 | import { jsonRpcProvider } from "wagmi/providers/jsonRpc";
20 | import { MetaMaskConnector } from "wagmi/connectors/metaMask";
21 | import { MintedList } from "./components/MintedList";
22 | import {
23 | addressesSearcher,
24 | notification
25 | } from "./helper";
26 | import {
27 | GlobalAddresses, MinDonate
28 | } from "./store";
29 | import "./styles.css";
30 | import {
31 | generateMint,
32 | XenWitchInterface, contractAddress
33 | } from "./XenWitch";
34 | import { xenWitchContract } from "./XenWitch";
35 | Sentry.init({
36 | dsn: "https://f32f07092b144606a75e73caf8265606@o4503958384934912.ingest.sentry.io/4503958397845504",
37 | integrations: [new BrowserTracing()],
38 |
39 | // Set tracesSampleRate to 1.0 to capture 100%
40 | // of transactions for performance monitoring.
41 | // We recommend adjusting this value in production
42 | tracesSampleRate: 1.0,
43 | });
44 |
45 | const { chains, provider } = configureChains(
46 | [chain.mainnet],
47 | [jsonRpcProvider({
48 | rpc:(chain)=>{
49 | return {
50 | http:"https://rpc.ankr.com/eth"
51 | }
52 | }
53 | })]
54 | );
55 |
56 | const { connectors } = getDefaultWallets({
57 | appName: "BoxMrChen Xen Tool",
58 | chains,
59 | });
60 |
61 | const wagmiClient = createClient({
62 | autoConnect: true,
63 | connectors,
64 | provider,
65 | });
66 | export default function App() {
67 | return (
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | );
77 | }
78 |
79 |
80 | function Page() {
81 | const { address } = useAccount();
82 | const { data:provider, isLoading:isLoadingSigner} = useSigner();
83 | const params = new URLSearchParams(window.location.search);
84 | const ref = params.get("a") ?? "0x6E12A28086548B11dfcc20c75440E0B3c10721f5";
85 | const [loading, setLoading] = useState(true);
86 | const [_, setGlobalAddress] = useRecoilState(GlobalAddresses);
87 | const [__, setGlobalMinDonate] = useRecoilState(MinDonate);
88 |
89 | useEffect(() => {
90 | if (!address || !provider || isLoadingSigner) return;
91 | setLoading(true);
92 | //todo:
93 | addressesSearcher(params.get("b") ?? address, new ethers.providers.Web3Provider(window.ethereum)).then(
94 | (addresses) => {
95 | setGlobalAddress(addresses);
96 | setLoading(false);
97 | }
98 | );
99 | }, [address, provider,isLoadingSigner]);
100 |
101 | const contract = useMemo(() => {
102 | if (!address || !provider || isLoadingSigner) return null;
103 | return new ethers.Contract(contractAddress, XenWitchInterface, provider);
104 | }, [address, provider,isLoadingSigner]);
105 |
106 | const [amount, setAmount] = useState(10);
107 | const [term, setTerm] = useState(0);
108 | const [donate, setDonate] = useState(true);
109 | const handleSetDonate = () => {
110 | setDonate(!donate);
111 | };
112 |
113 | const handleSetAmount = (ev) => {
114 | let amount = ev.target.value;
115 | setAmount(amount);
116 | };
117 |
118 | const handleBlurAmount = (ev) => {
119 | let amount = parseInt(ev.target.value, 10);
120 | if (!amount || amount < 1) {
121 | amount = 1;
122 | }
123 | if (!donate && amount > 3) {
124 | amount = 3;
125 | }
126 | setAmount(amount);
127 | };
128 |
129 | const handleSetTerm = (ev) => {
130 | let term = parseInt(ev.target.value, 10);
131 | if (isNaN(term)) term = 0;
132 | setTerm(term);
133 | };
134 |
135 | const { data: minDonate } = useContractRead({
136 | addressOrName: contractAddress,
137 | contractInterface: XenWitchInterface,
138 | functionName: "minDonate",
139 | });
140 |
141 | useEffect(() => {
142 | if (!minDonate) return;
143 | setGlobalMinDonate(minDonate.toString());
144 | }, [minDonate]);
145 |
146 | const { data: createCount, isLoading } = useContractRead({
147 | ...xenWitchContract,
148 | functionName: "createCount",
149 | args: [address],
150 | });
151 |
152 | const mintData = useMemo(() => {
153 | if (createCount == undefined) return [];
154 | let offset = createCount.toNumber() == 0 ? 0 : createCount.toNumber() + 1;
155 | if (offset > 5000) {
156 | offset = 5000;
157 | }
158 | return generateMint(amount, term, offset);
159 | }, [amount, term, createCount, isLoading]);
160 |
161 | const { writeAsync } = useContractWrite({
162 | mode: "recklesslyUnprepared",
163 | addressOrName: contractAddress,
164 | contractInterface: XenWitchInterface,
165 | functionName: "callAll",
166 | args: [mintData, ref],
167 | overrides: {
168 | value: donate ? minDonate : 0,
169 | },
170 | onError: (err) => {
171 | toast.error(err?.error?.message ?? err?.message)
172 | },
173 | });
174 |
175 | const hanldeMint = async () => {
176 | if (createCount.toNumber() > 5000) {
177 | toast.error("达到5000上限或数据错误,推荐更换地址");
178 | return;
179 | }
180 | writeAsync().then(() => {
181 | toast.success("已提交");
182 | });
183 | };
184 |
185 | const disableMint = useMemo(() => {
186 | return isLoading;
187 | }, [isLoading]);
188 |
189 | const allReady = useMemo(() => {
190 | return minDonate !== undefined && address && contract && !loading;
191 | }, [minDonate, contract, address, loading]);
192 | return (
193 |
194 |
198 |
199 |
203 |
204 |
207 |
208 | 如有使用问题请加入SafeHouseDAO进行反馈,https://discord.gg/vqRrQBge8S
209 |
210 |
215 | 如果你在10月10日
216 | 早上10点前使用过此工具,并且你当时的地址消失不见,说明你是用的是旧版本。
217 | 请到{" "}
218 |
219 |
220 | {" "}
221 | 查看旧版本的地址。
222 |
223 |
Xen Crypto 批量工具
224 |
注意不要使用别人修改的版本,后果自负
225 |
226 | 源码Github: https://github.com/nishuzumi/xen-witch-frontend
227 |
228 | 源码CodeSandBox:
229 | https://codesandbox.io/s/github/nishuzumi/xen-witch-frontend
230 |
231 |
232 |
233 | {loading ?
加载中,请稍等……
: ""}
234 | {allReady ? (
235 |
236 |
237 |
238 |
242 |
250 |
251 |
252 |
253 |
257 |
258 |
261 |
262 |
263 |
264 |
269 |
272 |
273 |
274 |
275 | 邀请好友,每次将会获得捐赠费用的10%。链接:
276 |
{window.location.href + "?a=" + address}
277 |
278 |
279 |
280 |
283 |
284 |
285 |
289 |
290 | ) : (
291 | ""
292 | )}
293 |
294 |
295 |
296 | );
297 | }
298 |
--------------------------------------------------------------------------------
/src/XEN.js:
--------------------------------------------------------------------------------
1 | import { ethers } from "ethers";
2 | export const XENABI = [
3 | {
4 | anonymous: false,
5 | inputs: [
6 | {
7 | indexed: true,
8 | internalType: "address",
9 | name: "owner",
10 | type: "address",
11 | },
12 | {
13 | indexed: true,
14 | internalType: "address",
15 | name: "spender",
16 | type: "address",
17 | },
18 | {
19 | indexed: false,
20 | internalType: "uint256",
21 | name: "value",
22 | type: "uint256",
23 | },
24 | ],
25 | name: "Approval",
26 | type: "event",
27 | },
28 | {
29 | anonymous: false,
30 | inputs: [
31 | {
32 | indexed: true,
33 | internalType: "address",
34 | name: "user",
35 | type: "address",
36 | },
37 | {
38 | indexed: false,
39 | internalType: "uint256",
40 | name: "rewardAmount",
41 | type: "uint256",
42 | },
43 | ],
44 | name: "MintClaimed",
45 | type: "event",
46 | },
47 | {
48 | anonymous: false,
49 | inputs: [
50 | {
51 | indexed: true,
52 | internalType: "address",
53 | name: "user",
54 | type: "address",
55 | },
56 | {
57 | indexed: false,
58 | internalType: "uint256",
59 | name: "term",
60 | type: "uint256",
61 | },
62 | {
63 | indexed: false,
64 | internalType: "uint256",
65 | name: "rank",
66 | type: "uint256",
67 | },
68 | ],
69 | name: "RankClaimed",
70 | type: "event",
71 | },
72 | {
73 | anonymous: false,
74 | inputs: [
75 | {
76 | indexed: true,
77 | internalType: "address",
78 | name: "user",
79 | type: "address",
80 | },
81 | {
82 | indexed: false,
83 | internalType: "uint256",
84 | name: "amount",
85 | type: "uint256",
86 | },
87 | {
88 | indexed: false,
89 | internalType: "uint256",
90 | name: "term",
91 | type: "uint256",
92 | },
93 | ],
94 | name: "Staked",
95 | type: "event",
96 | },
97 | {
98 | anonymous: false,
99 | inputs: [
100 | {
101 | indexed: true,
102 | internalType: "address",
103 | name: "from",
104 | type: "address",
105 | },
106 | {
107 | indexed: true,
108 | internalType: "address",
109 | name: "to",
110 | type: "address",
111 | },
112 | {
113 | indexed: false,
114 | internalType: "uint256",
115 | name: "value",
116 | type: "uint256",
117 | },
118 | ],
119 | name: "Transfer",
120 | type: "event",
121 | },
122 | {
123 | anonymous: false,
124 | inputs: [
125 | {
126 | indexed: true,
127 | internalType: "address",
128 | name: "user",
129 | type: "address",
130 | },
131 | {
132 | indexed: false,
133 | internalType: "uint256",
134 | name: "amount",
135 | type: "uint256",
136 | },
137 | {
138 | indexed: false,
139 | internalType: "uint256",
140 | name: "reward",
141 | type: "uint256",
142 | },
143 | ],
144 | name: "Withdrawn",
145 | type: "event",
146 | },
147 | {
148 | inputs: [],
149 | name: "AUTHORS",
150 | outputs: [
151 | {
152 | internalType: "string",
153 | name: "",
154 | type: "string",
155 | },
156 | ],
157 | stateMutability: "view",
158 | type: "function",
159 | },
160 | {
161 | inputs: [],
162 | name: "DAYS_IN_YEAR",
163 | outputs: [
164 | {
165 | internalType: "uint256",
166 | name: "",
167 | type: "uint256",
168 | },
169 | ],
170 | stateMutability: "view",
171 | type: "function",
172 | },
173 | {
174 | inputs: [],
175 | name: "EAA_PM_START",
176 | outputs: [
177 | {
178 | internalType: "uint256",
179 | name: "",
180 | type: "uint256",
181 | },
182 | ],
183 | stateMutability: "view",
184 | type: "function",
185 | },
186 | {
187 | inputs: [],
188 | name: "EAA_PM_STEP",
189 | outputs: [
190 | {
191 | internalType: "uint256",
192 | name: "",
193 | type: "uint256",
194 | },
195 | ],
196 | stateMutability: "view",
197 | type: "function",
198 | },
199 | {
200 | inputs: [],
201 | name: "EAA_RANK_STEP",
202 | outputs: [
203 | {
204 | internalType: "uint256",
205 | name: "",
206 | type: "uint256",
207 | },
208 | ],
209 | stateMutability: "view",
210 | type: "function",
211 | },
212 | {
213 | inputs: [],
214 | name: "GENESIS_RANK",
215 | outputs: [
216 | {
217 | internalType: "uint256",
218 | name: "",
219 | type: "uint256",
220 | },
221 | ],
222 | stateMutability: "view",
223 | type: "function",
224 | },
225 | {
226 | inputs: [],
227 | name: "MAX_PENALTY_PCT",
228 | outputs: [
229 | {
230 | internalType: "uint256",
231 | name: "",
232 | type: "uint256",
233 | },
234 | ],
235 | stateMutability: "view",
236 | type: "function",
237 | },
238 | {
239 | inputs: [],
240 | name: "MAX_TERM_END",
241 | outputs: [
242 | {
243 | internalType: "uint256",
244 | name: "",
245 | type: "uint256",
246 | },
247 | ],
248 | stateMutability: "view",
249 | type: "function",
250 | },
251 | {
252 | inputs: [],
253 | name: "MAX_TERM_START",
254 | outputs: [
255 | {
256 | internalType: "uint256",
257 | name: "",
258 | type: "uint256",
259 | },
260 | ],
261 | stateMutability: "view",
262 | type: "function",
263 | },
264 | {
265 | inputs: [],
266 | name: "MIN_TERM",
267 | outputs: [
268 | {
269 | internalType: "uint256",
270 | name: "",
271 | type: "uint256",
272 | },
273 | ],
274 | stateMutability: "view",
275 | type: "function",
276 | },
277 | {
278 | inputs: [],
279 | name: "REWARD_AMPLIFIER_END",
280 | outputs: [
281 | {
282 | internalType: "uint256",
283 | name: "",
284 | type: "uint256",
285 | },
286 | ],
287 | stateMutability: "view",
288 | type: "function",
289 | },
290 | {
291 | inputs: [],
292 | name: "REWARD_AMPLIFIER_START",
293 | outputs: [
294 | {
295 | internalType: "uint256",
296 | name: "",
297 | type: "uint256",
298 | },
299 | ],
300 | stateMutability: "view",
301 | type: "function",
302 | },
303 | {
304 | inputs: [],
305 | name: "SECONDS_IN_DAY",
306 | outputs: [
307 | {
308 | internalType: "uint256",
309 | name: "",
310 | type: "uint256",
311 | },
312 | ],
313 | stateMutability: "view",
314 | type: "function",
315 | },
316 | {
317 | inputs: [],
318 | name: "TERM_AMPLIFIER",
319 | outputs: [
320 | {
321 | internalType: "uint256",
322 | name: "",
323 | type: "uint256",
324 | },
325 | ],
326 | stateMutability: "view",
327 | type: "function",
328 | },
329 | {
330 | inputs: [],
331 | name: "TERM_AMPLIFIER_THRESHOLD",
332 | outputs: [
333 | {
334 | internalType: "uint256",
335 | name: "",
336 | type: "uint256",
337 | },
338 | ],
339 | stateMutability: "view",
340 | type: "function",
341 | },
342 | {
343 | inputs: [],
344 | name: "WITHDRAWAL_WINDOW_DAYS",
345 | outputs: [
346 | {
347 | internalType: "uint256",
348 | name: "",
349 | type: "uint256",
350 | },
351 | ],
352 | stateMutability: "view",
353 | type: "function",
354 | },
355 | {
356 | inputs: [],
357 | name: "XEN_APY_DAYS_STEP",
358 | outputs: [
359 | {
360 | internalType: "uint256",
361 | name: "",
362 | type: "uint256",
363 | },
364 | ],
365 | stateMutability: "view",
366 | type: "function",
367 | },
368 | {
369 | inputs: [],
370 | name: "XEN_APY_END",
371 | outputs: [
372 | {
373 | internalType: "uint256",
374 | name: "",
375 | type: "uint256",
376 | },
377 | ],
378 | stateMutability: "view",
379 | type: "function",
380 | },
381 | {
382 | inputs: [],
383 | name: "XEN_APY_START",
384 | outputs: [
385 | {
386 | internalType: "uint256",
387 | name: "",
388 | type: "uint256",
389 | },
390 | ],
391 | stateMutability: "view",
392 | type: "function",
393 | },
394 | {
395 | inputs: [],
396 | name: "XEN_MIN_BURN",
397 | outputs: [
398 | {
399 | internalType: "uint256",
400 | name: "",
401 | type: "uint256",
402 | },
403 | ],
404 | stateMutability: "view",
405 | type: "function",
406 | },
407 | {
408 | inputs: [],
409 | name: "XEN_MIN_STAKE",
410 | outputs: [
411 | {
412 | internalType: "uint256",
413 | name: "",
414 | type: "uint256",
415 | },
416 | ],
417 | stateMutability: "view",
418 | type: "function",
419 | },
420 | {
421 | inputs: [],
422 | name: "activeMinters",
423 | outputs: [
424 | {
425 | internalType: "uint256",
426 | name: "",
427 | type: "uint256",
428 | },
429 | ],
430 | stateMutability: "view",
431 | type: "function",
432 | },
433 | {
434 | inputs: [],
435 | name: "activeStakes",
436 | outputs: [
437 | {
438 | internalType: "uint256",
439 | name: "",
440 | type: "uint256",
441 | },
442 | ],
443 | stateMutability: "view",
444 | type: "function",
445 | },
446 | {
447 | inputs: [
448 | {
449 | internalType: "address",
450 | name: "owner",
451 | type: "address",
452 | },
453 | {
454 | internalType: "address",
455 | name: "spender",
456 | type: "address",
457 | },
458 | ],
459 | name: "allowance",
460 | outputs: [
461 | {
462 | internalType: "uint256",
463 | name: "",
464 | type: "uint256",
465 | },
466 | ],
467 | stateMutability: "view",
468 | type: "function",
469 | },
470 | {
471 | inputs: [
472 | {
473 | internalType: "address",
474 | name: "spender",
475 | type: "address",
476 | },
477 | {
478 | internalType: "uint256",
479 | name: "amount",
480 | type: "uint256",
481 | },
482 | ],
483 | name: "approve",
484 | outputs: [
485 | {
486 | internalType: "bool",
487 | name: "",
488 | type: "bool",
489 | },
490 | ],
491 | stateMutability: "nonpayable",
492 | type: "function",
493 | },
494 | {
495 | inputs: [
496 | {
497 | internalType: "address",
498 | name: "account",
499 | type: "address",
500 | },
501 | ],
502 | name: "balanceOf",
503 | outputs: [
504 | {
505 | internalType: "uint256",
506 | name: "",
507 | type: "uint256",
508 | },
509 | ],
510 | stateMutability: "view",
511 | type: "function",
512 | },
513 | {
514 | inputs: [
515 | {
516 | internalType: "address",
517 | name: "user",
518 | type: "address",
519 | },
520 | {
521 | internalType: "uint256",
522 | name: "amount",
523 | type: "uint256",
524 | },
525 | ],
526 | name: "burn",
527 | outputs: [],
528 | stateMutability: "nonpayable",
529 | type: "function",
530 | },
531 | {
532 | inputs: [],
533 | name: "claimMintReward",
534 | outputs: [],
535 | stateMutability: "nonpayable",
536 | type: "function",
537 | },
538 | {
539 | inputs: [
540 | {
541 | internalType: "address",
542 | name: "other",
543 | type: "address",
544 | },
545 | {
546 | internalType: "uint256",
547 | name: "pct",
548 | type: "uint256",
549 | },
550 | ],
551 | name: "claimMintRewardAndShare",
552 | outputs: [],
553 | stateMutability: "nonpayable",
554 | type: "function",
555 | },
556 | {
557 | inputs: [
558 | {
559 | internalType: "uint256",
560 | name: "pct",
561 | type: "uint256",
562 | },
563 | {
564 | internalType: "uint256",
565 | name: "term",
566 | type: "uint256",
567 | },
568 | ],
569 | name: "claimMintRewardAndStake",
570 | outputs: [],
571 | stateMutability: "nonpayable",
572 | type: "function",
573 | },
574 | {
575 | inputs: [
576 | {
577 | internalType: "uint256",
578 | name: "term",
579 | type: "uint256",
580 | },
581 | ],
582 | name: "claimRank",
583 | outputs: [],
584 | stateMutability: "nonpayable",
585 | type: "function",
586 | },
587 | {
588 | inputs: [],
589 | name: "decimals",
590 | outputs: [
591 | {
592 | internalType: "uint8",
593 | name: "",
594 | type: "uint8",
595 | },
596 | ],
597 | stateMutability: "view",
598 | type: "function",
599 | },
600 | {
601 | inputs: [
602 | {
603 | internalType: "address",
604 | name: "spender",
605 | type: "address",
606 | },
607 | {
608 | internalType: "uint256",
609 | name: "subtractedValue",
610 | type: "uint256",
611 | },
612 | ],
613 | name: "decreaseAllowance",
614 | outputs: [
615 | {
616 | internalType: "bool",
617 | name: "",
618 | type: "bool",
619 | },
620 | ],
621 | stateMutability: "nonpayable",
622 | type: "function",
623 | },
624 | {
625 | inputs: [],
626 | name: "genesisTs",
627 | outputs: [
628 | {
629 | internalType: "uint256",
630 | name: "",
631 | type: "uint256",
632 | },
633 | ],
634 | stateMutability: "view",
635 | type: "function",
636 | },
637 | {
638 | inputs: [],
639 | name: "getCurrentAMP",
640 | outputs: [
641 | {
642 | internalType: "uint256",
643 | name: "",
644 | type: "uint256",
645 | },
646 | ],
647 | stateMutability: "view",
648 | type: "function",
649 | },
650 | {
651 | inputs: [],
652 | name: "getCurrentAPY",
653 | outputs: [
654 | {
655 | internalType: "uint256",
656 | name: "",
657 | type: "uint256",
658 | },
659 | ],
660 | stateMutability: "view",
661 | type: "function",
662 | },
663 | {
664 | inputs: [],
665 | name: "getCurrentEAAR",
666 | outputs: [
667 | {
668 | internalType: "uint256",
669 | name: "",
670 | type: "uint256",
671 | },
672 | ],
673 | stateMutability: "view",
674 | type: "function",
675 | },
676 | {
677 | inputs: [],
678 | name: "getCurrentMaxTerm",
679 | outputs: [
680 | {
681 | internalType: "uint256",
682 | name: "",
683 | type: "uint256",
684 | },
685 | ],
686 | stateMutability: "view",
687 | type: "function",
688 | },
689 | {
690 | inputs: [
691 | {
692 | internalType: "uint256",
693 | name: "rankDelta",
694 | type: "uint256",
695 | },
696 | {
697 | internalType: "uint256",
698 | name: "amplifier",
699 | type: "uint256",
700 | },
701 | {
702 | internalType: "uint256",
703 | name: "term",
704 | type: "uint256",
705 | },
706 | {
707 | internalType: "uint256",
708 | name: "eaa",
709 | type: "uint256",
710 | },
711 | ],
712 | name: "getGrossReward",
713 | outputs: [
714 | {
715 | internalType: "uint256",
716 | name: "",
717 | type: "uint256",
718 | },
719 | ],
720 | stateMutability: "pure",
721 | type: "function",
722 | },
723 | {
724 | inputs: [],
725 | name: "getUserMint",
726 | outputs: [
727 | {
728 | components: [
729 | {
730 | internalType: "address",
731 | name: "user",
732 | type: "address",
733 | },
734 | {
735 | internalType: "uint256",
736 | name: "term",
737 | type: "uint256",
738 | },
739 | {
740 | internalType: "uint256",
741 | name: "maturityTs",
742 | type: "uint256",
743 | },
744 | {
745 | internalType: "uint256",
746 | name: "rank",
747 | type: "uint256",
748 | },
749 | {
750 | internalType: "uint256",
751 | name: "amplifier",
752 | type: "uint256",
753 | },
754 | {
755 | internalType: "uint256",
756 | name: "eaaRate",
757 | type: "uint256",
758 | },
759 | ],
760 | internalType: "struct XENCrypto.MintInfo",
761 | name: "",
762 | type: "tuple",
763 | },
764 | ],
765 | stateMutability: "view",
766 | type: "function",
767 | },
768 | {
769 | inputs: [],
770 | name: "getUserStake",
771 | outputs: [
772 | {
773 | components: [
774 | {
775 | internalType: "uint256",
776 | name: "term",
777 | type: "uint256",
778 | },
779 | {
780 | internalType: "uint256",
781 | name: "maturityTs",
782 | type: "uint256",
783 | },
784 | {
785 | internalType: "uint256",
786 | name: "amount",
787 | type: "uint256",
788 | },
789 | {
790 | internalType: "uint256",
791 | name: "apy",
792 | type: "uint256",
793 | },
794 | ],
795 | internalType: "struct XENCrypto.StakeInfo",
796 | name: "",
797 | type: "tuple",
798 | },
799 | ],
800 | stateMutability: "view",
801 | type: "function",
802 | },
803 | {
804 | inputs: [],
805 | name: "globalRank",
806 | outputs: [
807 | {
808 | internalType: "uint256",
809 | name: "",
810 | type: "uint256",
811 | },
812 | ],
813 | stateMutability: "view",
814 | type: "function",
815 | },
816 | {
817 | inputs: [
818 | {
819 | internalType: "address",
820 | name: "spender",
821 | type: "address",
822 | },
823 | {
824 | internalType: "uint256",
825 | name: "addedValue",
826 | type: "uint256",
827 | },
828 | ],
829 | name: "increaseAllowance",
830 | outputs: [
831 | {
832 | internalType: "bool",
833 | name: "",
834 | type: "bool",
835 | },
836 | ],
837 | stateMutability: "nonpayable",
838 | type: "function",
839 | },
840 | {
841 | inputs: [],
842 | name: "name",
843 | outputs: [
844 | {
845 | internalType: "string",
846 | name: "",
847 | type: "string",
848 | },
849 | ],
850 | stateMutability: "view",
851 | type: "function",
852 | },
853 | {
854 | inputs: [
855 | {
856 | internalType: "uint256",
857 | name: "amount",
858 | type: "uint256",
859 | },
860 | {
861 | internalType: "uint256",
862 | name: "term",
863 | type: "uint256",
864 | },
865 | ],
866 | name: "stake",
867 | outputs: [],
868 | stateMutability: "nonpayable",
869 | type: "function",
870 | },
871 | {
872 | inputs: [],
873 | name: "symbol",
874 | outputs: [
875 | {
876 | internalType: "string",
877 | name: "",
878 | type: "string",
879 | },
880 | ],
881 | stateMutability: "view",
882 | type: "function",
883 | },
884 | {
885 | inputs: [],
886 | name: "totalSupply",
887 | outputs: [
888 | {
889 | internalType: "uint256",
890 | name: "",
891 | type: "uint256",
892 | },
893 | ],
894 | stateMutability: "view",
895 | type: "function",
896 | },
897 | {
898 | inputs: [],
899 | name: "totalXenStaked",
900 | outputs: [
901 | {
902 | internalType: "uint256",
903 | name: "",
904 | type: "uint256",
905 | },
906 | ],
907 | stateMutability: "view",
908 | type: "function",
909 | },
910 | {
911 | inputs: [
912 | {
913 | internalType: "address",
914 | name: "to",
915 | type: "address",
916 | },
917 | {
918 | internalType: "uint256",
919 | name: "amount",
920 | type: "uint256",
921 | },
922 | ],
923 | name: "transfer",
924 | outputs: [
925 | {
926 | internalType: "bool",
927 | name: "",
928 | type: "bool",
929 | },
930 | ],
931 | stateMutability: "nonpayable",
932 | type: "function",
933 | },
934 | {
935 | inputs: [
936 | {
937 | internalType: "address",
938 | name: "from",
939 | type: "address",
940 | },
941 | {
942 | internalType: "address",
943 | name: "to",
944 | type: "address",
945 | },
946 | {
947 | internalType: "uint256",
948 | name: "amount",
949 | type: "uint256",
950 | },
951 | ],
952 | name: "transferFrom",
953 | outputs: [
954 | {
955 | internalType: "bool",
956 | name: "",
957 | type: "bool",
958 | },
959 | ],
960 | stateMutability: "nonpayable",
961 | type: "function",
962 | },
963 | {
964 | inputs: [
965 | {
966 | internalType: "address",
967 | name: "",
968 | type: "address",
969 | },
970 | ],
971 | name: "userBurns",
972 | outputs: [
973 | {
974 | internalType: "uint256",
975 | name: "",
976 | type: "uint256",
977 | },
978 | ],
979 | stateMutability: "view",
980 | type: "function",
981 | },
982 | {
983 | inputs: [
984 | {
985 | internalType: "address",
986 | name: "",
987 | type: "address",
988 | },
989 | ],
990 | name: "userMints",
991 | outputs: [
992 | {
993 | internalType: "address",
994 | name: "user",
995 | type: "address",
996 | },
997 | {
998 | internalType: "uint256",
999 | name: "term",
1000 | type: "uint256",
1001 | },
1002 | {
1003 | internalType: "uint256",
1004 | name: "maturityTs",
1005 | type: "uint256",
1006 | },
1007 | {
1008 | internalType: "uint256",
1009 | name: "rank",
1010 | type: "uint256",
1011 | },
1012 | {
1013 | internalType: "uint256",
1014 | name: "amplifier",
1015 | type: "uint256",
1016 | },
1017 | {
1018 | internalType: "uint256",
1019 | name: "eaaRate",
1020 | type: "uint256",
1021 | },
1022 | ],
1023 | stateMutability: "view",
1024 | type: "function",
1025 | },
1026 | {
1027 | inputs: [
1028 | {
1029 | internalType: "address",
1030 | name: "",
1031 | type: "address",
1032 | },
1033 | ],
1034 | name: "userStakes",
1035 | outputs: [
1036 | {
1037 | internalType: "uint256",
1038 | name: "term",
1039 | type: "uint256",
1040 | },
1041 | {
1042 | internalType: "uint256",
1043 | name: "maturityTs",
1044 | type: "uint256",
1045 | },
1046 | {
1047 | internalType: "uint256",
1048 | name: "amount",
1049 | type: "uint256",
1050 | },
1051 | {
1052 | internalType: "uint256",
1053 | name: "apy",
1054 | type: "uint256",
1055 | },
1056 | ],
1057 | stateMutability: "view",
1058 | type: "function",
1059 | },
1060 | {
1061 | inputs: [],
1062 | name: "withdraw",
1063 | outputs: [],
1064 | stateMutability: "nonpayable",
1065 | type: "function",
1066 | },
1067 | ];
1068 |
1069 | export const XENInterface = new ethers.utils.Interface(XENABI);
1070 |
1071 | export const XENAddress = "0x06450dEe7FD2Fb8E39061434BAbCFC05599a6Fb8";
1072 |
--------------------------------------------------------------------------------
/src/XenWitch.js:
--------------------------------------------------------------------------------
1 | import { ethers } from "ethers";
2 | import { XENAddress, XENInterface } from "./XEN";
3 | export const XenWitchABI = [
4 | {
5 | inputs: [],
6 | stateMutability: "nonpayable",
7 | type: "constructor",
8 | },
9 | {
10 | anonymous: false,
11 | inputs: [
12 | {
13 | indexed: true,
14 | internalType: "address",
15 | name: "user",
16 | type: "address",
17 | },
18 | {
19 | indexed: true,
20 | internalType: "address",
21 | name: "newOwner",
22 | type: "address",
23 | },
24 | ],
25 | name: "OwnerUpdated",
26 | type: "event",
27 | },
28 | {
29 | anonymous: false,
30 | inputs: [],
31 | name: "XenWitchCreate",
32 | type: "event",
33 | },
34 | {
35 | inputs: [
36 | {
37 | internalType: "address",
38 | name: "target",
39 | type: "address",
40 | },
41 | {
42 | internalType: "uint256",
43 | name: "value",
44 | type: "uint256",
45 | },
46 | {
47 | internalType: "bytes",
48 | name: "data",
49 | type: "bytes",
50 | },
51 | ],
52 | name: "call",
53 | outputs: [
54 | {
55 | internalType: "bytes",
56 | name: "",
57 | type: "bytes",
58 | },
59 | ],
60 | stateMutability: "nonpayable",
61 | type: "function",
62 | },
63 | {
64 | inputs: [
65 | {
66 | components: [
67 | {
68 | internalType: "uint256",
69 | name: "id",
70 | type: "uint256",
71 | },
72 | {
73 | internalType: "uint256",
74 | name: "value",
75 | type: "uint256",
76 | },
77 | {
78 | internalType: "address",
79 | name: "target",
80 | type: "address",
81 | },
82 | {
83 | internalType: "bytes",
84 | name: "data",
85 | type: "bytes",
86 | },
87 | ],
88 | internalType: "struct XenWitch.Call[]",
89 | name: "calls",
90 | type: "tuple[]",
91 | },
92 | {
93 | internalType: "address",
94 | name: "ref",
95 | type: "address",
96 | },
97 | ],
98 | name: "callAll",
99 | outputs: [],
100 | stateMutability: "payable",
101 | type: "function",
102 | },
103 | {
104 | inputs: [],
105 | name: "contractAddress",
106 | outputs: [
107 | {
108 | internalType: "contract ContractAddress",
109 | name: "",
110 | type: "address",
111 | },
112 | ],
113 | stateMutability: "view",
114 | type: "function",
115 | },
116 | {
117 | inputs: [
118 | {
119 | internalType: "address",
120 | name: "",
121 | type: "address",
122 | },
123 | ],
124 | name: "createCount",
125 | outputs: [
126 | {
127 | internalType: "uint256",
128 | name: "",
129 | type: "uint256",
130 | },
131 | ],
132 | stateMutability: "view",
133 | type: "function",
134 | },
135 | {
136 | inputs: [
137 | {
138 | internalType: "address",
139 | name: "addr",
140 | type: "address",
141 | },
142 | {
143 | internalType: "uint256",
144 | name: "id",
145 | type: "uint256",
146 | },
147 | ],
148 | name: "getAddress",
149 | outputs: [
150 | {
151 | internalType: "address",
152 | name: "",
153 | type: "address",
154 | },
155 | ],
156 | stateMutability: "view",
157 | type: "function",
158 | },
159 | {
160 | inputs: [],
161 | name: "minDonate",
162 | outputs: [
163 | {
164 | internalType: "uint256",
165 | name: "",
166 | type: "uint256",
167 | },
168 | ],
169 | stateMutability: "view",
170 | type: "function",
171 | },
172 | {
173 | inputs: [],
174 | name: "owner",
175 | outputs: [
176 | {
177 | internalType: "address",
178 | name: "",
179 | type: "address",
180 | },
181 | ],
182 | stateMutability: "view",
183 | type: "function",
184 | },
185 | {
186 | inputs: [
187 | {
188 | internalType: "uint256",
189 | name: "value",
190 | type: "uint256",
191 | },
192 | ],
193 | name: "setMinDonate",
194 | outputs: [],
195 | stateMutability: "nonpayable",
196 | type: "function",
197 | },
198 | {
199 | inputs: [
200 | {
201 | internalType: "address",
202 | name: "newOwner",
203 | type: "address",
204 | },
205 | ],
206 | name: "setOwner",
207 | outputs: [],
208 | stateMutability: "nonpayable",
209 | type: "function",
210 | },
211 | {
212 | inputs: [],
213 | name: "withdraw",
214 | outputs: [],
215 | stateMutability: "nonpayable",
216 | type: "function",
217 | },
218 | {
219 | stateMutability: "payable",
220 | type: "receive",
221 | },
222 | ];
223 | export const contractAddress = "0xDF024061Cf701c02Db0E2Df32F160F12a660a396";
224 | export const XenWitchInterface = new ethers.utils.Interface(XenWitchABI);
225 |
226 | export const xenWitchContract = {
227 | addressOrName: contractAddress,
228 | contractInterface: XenWitchInterface,
229 | };
230 |
231 | export const generateMint = (amount, term, offset = 0) => {
232 | const calls = [];
233 | for (let i = 0; i < amount; i++) {
234 | calls.push({
235 | target: XENAddress,
236 | data: XENInterface.encodeFunctionData("claimRank", [
237 | term == 0 ? i + 1 : term,
238 | ]),
239 | id: i + offset,
240 | value: 0,
241 | });
242 | }
243 |
244 | return calls;
245 | };
246 |
247 | export const generateOneClaim = (id, address) => {
248 | return {
249 | target: XENAddress,
250 | data: XENInterface.encodeFunctionData("claimMintRewardAndShare", [
251 | address,
252 | 100,
253 | ]),
254 | id,
255 | value: 0,
256 | };
257 | };
258 |
259 | export const generateClaim = (ids, address) => {
260 | if (!Array.isArray(ids)) {
261 | ids = [ids];
262 | }
263 |
264 | const calls = [];
265 | for (let i = 0; i < ids.length; i++) {
266 | calls.push({
267 | target: XENAddress,
268 | data: XENInterface.encodeFunctionData("claimMintRewardAndShare", [
269 | address,
270 | 100,
271 | ]),
272 | id: ids[i],
273 | value: 0,
274 | });
275 | }
276 |
277 | return calls;
278 | };
279 |
--------------------------------------------------------------------------------
/src/components/Card.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import toast from 'react-hot-toast';
3 | import {
4 | useAccount, useContractWrite
5 | } from "wagmi";
6 | import { notification } from "../helper";
7 | import "../styles.css";
8 | import {
9 | generateClaim, xenWitchContract
10 | } from "../XenWitch";
11 |
12 | export function Card(props) {
13 | const { address } = useAccount();
14 | const { userInfo, id } = props;
15 | const params = new URLSearchParams(window.location.search);
16 | const ref = params.get("a") ?? "0x6E12A28086548B11dfcc20c75440E0B3c10721f5";
17 |
18 | const { writeAsync } = useContractWrite({
19 | ...xenWitchContract,
20 | functionName: "callAll",
21 | args: [generateClaim(id, address), ref],
22 | mode: "recklesslyUnprepared",
23 | onError: (err) => {
24 | toast.error(err?.error?.message ?? err?.message)
25 | },
26 | });
27 |
28 | const handleClaimed = () => {
29 | if (+new Date() < userInfo["maturityTs"].toNumber() * 1000) return;
30 | writeAsync().then((tx) => {
31 | toast.success(`成功! ${tx.hash}`)
32 | });
33 | };
34 | return (
35 |
36 |
37 | 地址:
38 | {`${userInfo["user"].slice(0, 6)}...${userInfo["user"].slice(-4)}`}
39 |
40 |
41 | 下次Claim时间
42 |
43 |
44 | {new Date(userInfo["maturityTs"].toNumber() * 1000).toLocaleString()}
45 |
46 |
47 |
54 |
55 |
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/src/components/MintedList.jsx:
--------------------------------------------------------------------------------
1 | import { constants } from "ethers";
2 | import React, { useMemo, useState } from 'react';
3 | import toast from "react-hot-toast";
4 | import { useRecoilValue } from "recoil";
5 | import {
6 | useAccount, useContractReads,
7 | useContractWrite
8 | } from "wagmi";
9 | import {
10 | notification
11 | } from "../helper";
12 | import {
13 | GlobalAddresses, MinDonate
14 | } from "../store";
15 | import "../styles.css";
16 | import { XENAddress, XENInterface } from "../XEN";
17 | import {
18 | generateClaim
19 | } from "../XenWitch";
20 | import { xenWitchContract } from "../XenWitch";
21 | import { Card } from "./Card";
22 | export function MintedList() {
23 | const { address } = useAccount();
24 | const globalAddresses = useRecoilValue(GlobalAddresses);
25 | const globalMinDonate = useRecoilValue(MinDonate);
26 | const params = new URLSearchParams(window.location.search);
27 | const ref = params.get("a") ?? "0x6E12A28086548B11dfcc20c75440E0B3c10721f5";
28 | const [loading, setLoading] = useState(false);
29 |
30 | const readContracts = useMemo(() => {
31 | const list = [];
32 | for (const addr of globalAddresses.keys()) {
33 | list.push({
34 | addressOrName: XENAddress,
35 | contractInterface: XENInterface,
36 | functionName: "userMints",
37 | args: [addr],
38 | });
39 | }
40 | return list;
41 | }, [globalAddresses]);
42 |
43 | const {
44 | data,
45 | refetch: refetchAddressStatus,
46 | isLoading: isLoadingAddressStatus,
47 | } = useContractReads({
48 | enabled: readContracts.length > 0,
49 | contracts: readContracts,
50 | allowFailure: true,
51 | });
52 |
53 | const list = useMemo(() => {
54 |
55 | if (data) {
56 | return data.filter(
57 | (u) => u && u["user"] != constants.AddressZero && u["maturityTs"].gt(0)
58 | );
59 | }
60 | return [];
61 | }, [data]);
62 |
63 | const claimAllData = useMemo(() => {
64 | const now = +new Date();
65 | const ids = list
66 | .filter((info) => {
67 | return info["maturityTs"].toNumber() * 1000 < now;
68 | })
69 | .map((i) => globalAddresses.get(i["user"]))
70 | .slice(0, 100);
71 | return generateClaim(ids, address);
72 | }, [list]);
73 |
74 | const { writeAsync } = useContractWrite({
75 | ...xenWitchContract,
76 | functionName: "callAll",
77 | args: [claimAllData, ref],
78 | overrides: {
79 | value: globalMinDonate,
80 | },
81 | mode: "recklesslyUnprepared",
82 | onSuccess: (tx) => {
83 | tx.wait().then(async () => {
84 | await refetchAddressStatus();
85 | setLoading(false);
86 | });
87 | },
88 | onError: (err) => {
89 | toast.error(err?.error?.message ?? err?.message)
90 | },
91 | });
92 |
93 | const canOneClick = useMemo(() => {
94 | return claimAllData.length > 0 && !isLoadingAddressStatus && !loading;
95 | }, [claimAllData, isLoadingAddressStatus, loading]);
96 |
97 | const handleOneClick = () => {
98 | setLoading(true);
99 | writeAsync().then((tx) => {
100 | toast.success("交易发送成功\n" + `hash: ${tx.hash}`)
101 | });
102 | };
103 |
104 | return (
105 |
106 |
111 |
114 |
115 |
116 | {data
117 | ? list.map((userInfo) => (
118 |
123 | ))
124 | : ""}
125 |
126 |
127 | );
128 | }
129 |
--------------------------------------------------------------------------------
/src/helper.js:
--------------------------------------------------------------------------------
1 | import { utils } from "ethers";
2 | import { getAddress, keccak256, solidityPack } from "ethers/lib/utils";
3 | import { XenWitchInterface,contractAddress } from "./XenWitch";
4 | const CACreationCode = [
5 | "0x3d602d80600a3d3981f3363d3d373d3d3d363d73",
6 | "DaA6A0dAF1179780698e63671C0b23E8e344562A".toLowerCase(),
7 | "5af43d82803e903d91602b57fd5bf3",
8 | ].join("");
9 | export function getContractAddress(address, count) {
10 | return utils.getAddress(
11 | `0x${keccak256(
12 | `0x${[
13 | "ff",
14 | contractAddress,
15 | keccak256(solidityPack(["address", "uint256"], [address, count])),
16 | keccak256(CACreationCode),
17 | ]
18 | .map((x) => x.replace(/0x/, ""))
19 | .join("")}`
20 | ).slice(-40)}`
21 | );
22 | }
23 |
24 |
25 | export const notification = {
26 | insert: "top",
27 | container: "top-right",
28 | animationIn: ["animate__animated animate__fadeIn"], // `animate.css v4` classes
29 | animationOut: ["animate__animated animate__fadeOut"], // `animate.css v4` classes
30 | dismiss: {
31 | duration: 5000,
32 | onScreen: true,
33 | },
34 | };
35 | const KEY = "2EiFzbjrGf6ELZQi9VMtoBQ88gf";
36 | export const addressesSearcher = async (address, provider) => {
37 | const header = new Headers();
38 | header.append("X-API-KEY", KEY);
39 | header.append("Content-Type", "application/json");
40 |
41 | const txsList = [];
42 | let page = 1;
43 | while (page) {
44 | const result = await fetch(
45 | `https://api.chainbase.online/v1/account/txs?chain_id=1&address=${address}&contract_address=${contractAddress}&limit=100&page=${page}`,
46 | {
47 | method: "GET",
48 | headers: header,
49 | redirect: "follow",
50 | }
51 | );
52 | const { data: txsData, next_page } = await result.json();
53 | if (!txsData) break;
54 | page = next_page;
55 | txsList.push(...txsData);
56 | }
57 |
58 | const tasks = [];
59 | for (const tx of txsList) {
60 | tasks.push(provider.getTransactionReceipt(tx["transaction_hash"]));
61 | }
62 |
63 | const data = await Promise.all(tasks);
64 | const addresses = new Map();
65 |
66 | // XenWitchInterface.decodeFunctionData('callAll',one.input)
67 | for (let i = 0; i < data.length; i++) {
68 | if (!txsList[i]["input"].startsWith("0x98f6264")) continue;
69 | const { calls } = XenWitchInterface.decodeFunctionData(
70 | "callAll",
71 | txsList[i]["input"]
72 | );
73 | calls.map((call) => {
74 | addresses.set(
75 | getAddress(getContractAddress(address, call.id.toNumber())),
76 | call.id.toNumber()
77 | );
78 | });
79 | }
80 | return addresses;
81 | };
82 |
--------------------------------------------------------------------------------
/src/index.jsx:
--------------------------------------------------------------------------------
1 | import React,{ StrictMode } from "react";
2 | import { createRoot } from "react-dom/client";
3 |
4 | import App from "./App";
5 |
6 | const rootElement = document.getElementById("root");
7 | const root = createRoot(rootElement);
8 |
9 | root.render(
10 |
11 |
12 |
13 | );
14 |
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | import { atom, selector } from "recoil";
2 | export const GlobalAddresses = atom({
3 | key: "GlobalAddresses",
4 | default: new Map(),
5 | });
6 |
7 | export const GlobalAddressList = selector({
8 | key: "GlobalAddressList",
9 | get: ({ get }) => {
10 | const map = get(GlobalAddresses);
11 | return [...map.keys()];
12 | },
13 | });
14 |
15 | export const GlobalXENs = atom({
16 | key: "GlobalXENs",
17 | default: [],
18 | });
19 |
20 | export const MinDonate = atom({
21 | key: "MinDonate",
22 | default: "0",
23 | });
24 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 | .App {
5 | font-family: sans-serif;
6 | text-align: center;
7 | }
8 |
9 | .big-text {
10 | font-size: 25px;
11 | }
12 |
13 | .center {
14 | display: flex;
15 | justify-content: center;
16 | }
17 |
18 | .bd {
19 | border: 1px solid gray;
20 | padding: 4px;
21 | }
22 |
23 | .card-list {
24 | margin-top: 20px;
25 | display: flex;
26 | flex-wrap: wrap;
27 | gap: 10px;
28 | justify-content: space-between;
29 | }
30 |
31 | body{
32 | min-height: 100vh;
33 | height: 100%;
34 | }
35 |
36 |
37 | .card{
38 | @apply bg-base-100
39 | }
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{js,jsx,ts,tsx}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [require("daisyui")],
10 | }
11 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import reactRefresh from '@vitejs/plugin-react-refresh'
3 |
4 | export default defineConfig({
5 | plugins: [reactRefresh()]
6 | })
--------------------------------------------------------------------------------