Repository navigation
Expand file tree
/
Copy pathcheck.html
More file actions
765 lines (729 loc) · 67.7 KB
/
Copy pathcheck.html
File metadata and controls
765 lines (729 loc) · 67.7 KB
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Token & project check — how far can you trust it? · Base.tools</title>
<meta name="description" content="Paste a Base or Robinhood Chain token address and get a trust score from 1 to 10 for the token and for the project behind it: can you sell it, who launched it, which holders got coins straight from the deployer, what a $500 exit returns — and audit, team, investors, docs, GitHub activity, socials and a working product, each with its source.">
<meta property="og:title" content="Token & project check — trust score 1 to 10">
<meta property="og:description" content="Paste a token address. The token: sell simulation, deployer, insider holders, real exit. The project: audit, team, investors, docs, GitHub, socials, product — each linked.">
<meta property="og:type" content="website">
<meta property="og:site_name" content="Base.tools">
<meta property="og:url" content="https://deftools.xyz/check.html">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@Def7771">
<link rel="canonical" href="https://deftools.xyz/check.html">
<meta name="theme-color" content="#0a0e1c">
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%233b6eff'/%3E%3C/svg%3E">
<style>
:root{
--bg:#0a0e1c; --bg2:#0d1226; --card:#111730; --border:#232c4d; --border-hover:#33406b;
--blue:#3b6eff; --blue-text:#7ea0ff; --blue-bright:#9db8ff;
--yellow:#ffcf40; --green:#3fbf87; --red:#ff6b6b; --orange:#ff9f43;
--text:#eef1fb; --muted:#8791b3; --muted2:#7a84a8;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0; background:var(--bg); color:var(--text);
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; line-height:1.55; -webkit-font-smoothing:antialiased}
a{color:var(--blue-text); text-decoration:none}
a:hover{color:var(--blue-bright)}
.wrap{max-width:860px; margin:0 auto; padding:0 16px}
header{border-bottom:1px solid var(--border); background:var(--bg2)}
.head-in{display:flex; align-items:center; justify-content:space-between; gap:16px; padding-block:14px; flex-wrap:wrap}
.back{display:inline-flex; align-items:center; min-height:32px; font-size:14px; color:var(--muted)}
.lang{display:flex; gap:4px}
.lang button{background:none; border:1px solid var(--border); color:var(--muted); border-radius:8px; padding:4px 10px; font-size:13px; cursor:pointer; min-height:32px}
.lang button.on{border-color:var(--blue); color:var(--text)}
.quota{margin:22px 0 0; background:var(--card); border:1px solid var(--border); border-left:3px solid var(--yellow);
border-radius:12px; padding:12px 16px; font-size:14.5px; color:var(--muted)}
.quota b{color:var(--text)}
.hero{padding:22px 0 8px}
h1{margin:0 0 8px; font-size:30px; line-height:1.2; letter-spacing:-.02em}
.sub{margin:0; color:var(--muted); font-size:16px; max-width:64ch}
form{display:flex; gap:10px; margin:20px 0 6px; flex-wrap:wrap}
input{flex:1 1 320px; min-width:0; background:var(--card); border:1px solid var(--border); color:var(--text);
border-radius:12px; padding:14px 16px; font-size:15px; font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
input:focus{outline:none; border-color:var(--blue)}
button.go{background:var(--blue); color:#fff; border:0; border-radius:12px; padding:0 26px; font-size:16px; font-weight:600;
cursor:pointer; min-height:50px}
button.go:disabled{opacity:.5; cursor:default}
.hint{color:var(--muted2); font-size:13px; margin:0}
.pay{margin:18px 0 0; background:var(--card); border:1px solid var(--border); border-left:3px solid var(--blue); border-radius:12px; padding:16px 18px}
.pay h2{font-size:16px; margin:0 0 6px}
.pay p{margin:4px 0; font-size:14.5px; color:var(--muted)}
.packs{display:flex; gap:10px; flex-wrap:wrap; margin:12px 0 6px}
.packs button{flex:1 1 150px; background:var(--bg2); border:1px solid var(--border-hover); color:var(--text); border-radius:12px;
padding:12px 14px; font-size:15px; cursor:pointer; min-height:48px}
.packs button:hover{border-color:var(--blue)}
.packs button:disabled{opacity:.5; cursor:default}
.packs b{display:block; font-size:17px}
.paystat{font-size:14px; margin-top:8px}
.paystat.bad{color:var(--red)} .paystat.ok{color:var(--green)}
.steps{margin:22px 0 0; display:grid; gap:6px}
.step{font-size:14.5px; color:var(--muted)}
.step.done{color:var(--text)}
.step.now::after{content:' …'; animation:blink 1s infinite}
@keyframes blink{50%{opacity:.2}}
.report{margin:24px 0 10px}
.head{display:flex; align-items:baseline; gap:10px; flex-wrap:wrap}
.head .sym{font-size:24px; font-weight:700}
.head .nm{color:var(--muted)}
.addr{font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:12.5px; color:var(--muted2); word-break:break-all}
.score{margin:16px 0 4px; padding:14px 18px; border-radius:12px; font-size:20px; font-weight:700; border:1px solid var(--border)}
.score.t1{background:rgba(255,107,107,.12); border-color:rgba(255,107,107,.45)}
.score.t2{background:rgba(255,159,67,.12); border-color:rgba(255,159,67,.45)}
.score.t3{background:rgba(255,207,64,.1); border-color:rgba(255,207,64,.4)}
.score.t4{background:rgba(63,191,135,.1); border-color:rgba(63,191,135,.4)}
.bar{display:flex; gap:3px; margin-top:10px}
.bar i{flex:1; height:6px; border-radius:3px; background:var(--border)}
.bar i.on{background:currentColor}
.scale{color:var(--muted2); font-size:13px; margin:6px 0 4px}
h3{font-size:15px; margin:16px 0 6px}
ul.find{list-style:none; padding:0; margin:0 0 6px; display:grid; gap:5px}
ul.find li{font-size:15px}
section.card{background:var(--card); border:1px solid var(--border); border-radius:12px; padding:16px 18px; margin-top:14px}
section.card h2{font-size:16px; margin:0 0 10px; letter-spacing:-.01em}
section.card p{margin:4px 0; font-size:14.5px}
.note{color:var(--muted2); font-size:13px}
.rights{border-left:3px solid var(--border-hover)}
.proj p{white-space:pre-wrap}
.parts{font-size:15px; font-weight:600; margin:8px 0 0}
.proj .pscore{font-weight:600; font-size:15px; margin-bottom:6px}
.proj h3.pgroup{font-size:13px; text-transform:uppercase; letter-spacing:.06em; color:var(--muted2); margin:12px 0 4px}
.proj .ptext{margin-top:14px; padding-top:12px; border-top:1px solid var(--border)}.share{margin-top:14px; background:none; border:1px solid var(--border-hover); color:var(--text); border-radius:10px; padding:8px 14px; font-size:14px; cursor:pointer; min-height:40px}
.err{background:var(--card); border:1px solid var(--border); border-left:3px solid var(--red); border-radius:12px; padding:14px 16px; margin-top:18px}
footer{border-top:1px solid var(--border); margin-top:34px; padding:22px 0 40px; color:var(--muted2); font-size:13.5px}
@media (max-width:640px){ h1{font-size:24px} .score{font-size:18px} button.go{flex:1 1 100%} }
</style>
</head>
<body>
<header>
<div class="wrap head-in">
<a class="back" href="/">← Base.tools</a>
<div class="lang"><button id="l-en" type="button">EN</button><button id="l-ru" type="button">RU</button></div>
</div>
</header>
<div class="wrap">
<div class="quota" id="quota"></div>
<div class="hero">
<h1 id="t-title"></h1>
<p class="sub" id="t-sub"></p>
</div>
<form id="f">
<input id="addr" autocomplete="off" spellcheck="false" placeholder="0x…">
<button class="go" id="go" type="submit"></button>
</form>
<p class="hint" id="t-hint"></p>
<div class="pay" id="pay" hidden></div>
<div class="steps" id="steps"></div>
<div id="out"></div>
</div>
<footer>
<div class="wrap" id="t-foot"></div>
</footer>
<script src="check.js"></script>
<script>
(function () {
// The Worker holds the AI keys, counts the free checks and credits the paid
// ones. Until it answers, the page still works: the on-chain check runs here
// and the free limit is kept locally.
var WORKER = 'https://deftools-check.araxis67.workers.dev';
var LIMIT = 3;
// Paid checks: USDC goes straight to his wallet; the calldata carries his Base
// builder code (ERC-8021 suffix for bc_mrkwu2m0) so Base counts every payment.
var PAY_TO = '0x335A503B743B569Ef1a9E6Acc95F70307Af146B0';
var USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
var BUILDER_SUFFIX = '62635f6d726b7775326d300b0080218021802180218021802180218021';
var PACKS = [1, 5, 10];
var T = {
en: {
title: 'Token & project check: how far can you trust this token and the team behind it', go: 'Check',
sub: 'Paste a Base or Robinhood Chain token address. In about a minute you get a trust score from 1 to 10 for the token and for the project, and one overall. The token: can you actually sell it, who launched it and what became of their earlier coins, which big holders got coins straight from the deployer, what a $500 exit really returns. The project: audit, team, investors, docs, GitHub activity, socials, a working product — every point with its source.',
hint: 'The score is a risk check, not advice. The decision is yours.',
quota: function (q) {
if (q.owner) return '<b>Unlimited checks</b> — owner access.';
var s = q.left > 0 ? '<b>' + LIMIT + ' free checks a day.</b> Left today: <b>' + q.left + '</b>.' : '<b>Free checks for today are used up.</b> They come back at midnight UTC.';
if (q.credits > 0) s += ' Paid checks: <b>' + q.credits + '</b>.';
else s += ' More: 0.1 USDC per check.';
return s;
},
badAddr: 'That does not look like a token address (0x followed by 40 characters).',
steps: { market: 'Finding the token and its pools', contract: 'Reading the contract and simulating a sale', people: 'Tracing the deployer, holders and first buyers', project: 'Reading about the project' },
notfound: 'No such token on exchanges or in the Base and Robinhood Chain block explorers. Check the address.',
dead: function (d) { return '🔴 TRUST 1/10 — ' + d.symbol + ' (' + d.name + ') exists on ' + (d.chain === 'base' ? 'Base' : 'Robinhood Chain') + ', but there is nowhere to trade it: not a single live pool. The liquidity has been pulled — the coin is dead.'; },
chain: function (c) { return 'This token trades on ' + c + '. For now only Base and Robinhood Chain are checked.'; },
trust: 'TRUST', labels: ['very low — almost certainly a trap', 'low', 'medium', 'high', 'very high'],
scale: '10 — the most trust, 1 — almost certainly a trap. The decision is yours.',
lowers: 'Lowers trust', raises: 'Raises trust',
market: 'Market', contract: 'Contract and liquidity', who: 'Who launched it', holders: 'Holders', project: 'Project',
rightsTitle: 'Team rights — a note, not an alarm',
rightsNote: 'Large projects usually keep control with the team, and pools, staking and treasury sit among the top holders. That is a question of trust in the team, not a sign of a trap:',
base: 'About 1 in 50 new Base coins still trades two weeks later (our count, 23.09.2026). This is a risk check, not advice to buy.',
share: 'Copy link to this report', copied: 'Link copied',
foot: 'Checks run in your browser against public data: DexScreener, GoPlus, honeypot.is, GeckoTerminal, Blockscout, KyberSwap, CoinGecko. The project read is written by an AI from sources it lists. Code: <a href="https://github.com/araxis33/meme-scout" target="_blank" rel="noopener">github.com/araxis33/meme-scout</a>. Part of <a href="/">Base.tools</a>.',
projWait: 'Reading the project…', projOff: 'The project read is not available right now — the on-chain check above is complete.',
parts: function (tk, pj) { return 'Token ' + tk + '/10 · ' + (pj === undefined ? 'project: checking…' : pj === null ? 'project: not checked, the score is the token only' : 'Project ' + pj + '/10'); },
pj: {
score: function (s, n) { return 'Project ' + s + '/10 — ' + n + ' of 9 criteria found'; },
code: 'Code', team: 'Team', dev: 'Development', community: 'Community', product: 'Product', market: 'Market', spread: 'Distribution',
auditYes: function (by) { return 'Audit' + (by ? ': ' + by : ' found'); }, auditNo: 'No audit found in open sources',
srcOpen: 'Contract source published', srcHidden: 'Contract source hidden',
teamPublic: 'Team is public — names are known', teamAnon: 'The team says it is anonymous', teamNo: 'Team names not found',
invYes: 'Has investors', invNo: 'No investors found',
docsYes: 'Documentation', docsNo: 'No documentation found',
domain: function (date, d) { return 'Site domain registered ' + date + ' (' + (d >= 365 ? Math.floor(d / 365) + (d >= 730 ? ' years' : ' year') : Math.round(d / 30) + ' months') + ' ago)'; },
domainNo: 'Site domain age unknown', noSite: 'No project site found',
ghActive: function (n, repo) { return 'GitHub: ' + n + (n >= 100 ? '+' : '') + ' commits in 30 days (' + repo + ')'; },
ghQuiet: function (date, repo) { return 'GitHub: last commit ' + date + ' (' + repo + ')'; },
ghNo: 'No GitHub found',
xYes: 'X account', xNo: 'No X account found', chatYes: 'Telegram or Discord', chatNo: 'No Telegram or Discord found',
prodLive: 'Working product people can use', prodNone: 'No product — only a coin', prodNo: 'A working product is not confirmed',
marketLine: function (t) { return tierLine(t) || '—'; },
vest: function (p) { return 'in vesting or lock contracts: ' + p0(p); }, safe: function (p) { return 'in team multisigs: ' + p0(p); },
top10: function (p) { return '10 largest wallets (not exchanges or contracts): ' + p0(p); },
},
payTitle: 'More checks — 0.1 USDC each',
payText: 'Pay from your wallet on Base. The USDC goes straight to the author of this tool; checks you buy do not expire.',
pack: function (n) { return '<b>' + n + (n === 1 ? ' check' : ' checks') + '</b>' + (n * 0.1).toFixed(1) + ' USDC'; },
noWallet: 'No wallet in this browser. Open the page in Coinbase Wallet or MetaMask, or install one.',
wait: 'Confirm the payment in your wallet…', sent: 'Payment sent — waiting for Base to confirm it…',
done: function (n, c) { return 'Paid. Added ' + n + (n === 1 ? ' check' : ' checks') + ' — you now have ' + c + '.'; },
lowUsdc: 'Not enough USDC on Base in this wallet.', payFail: function (m) { return 'Payment did not go through: ' + m; },
},
ru: {
title: 'Проверка токена и проекта: насколько можно доверять токену и команде за ним', go: 'Проверить',
sub: 'Вставь адрес токена в сети Base или Robinhood Chain. Примерно за минуту — оценка от 1 до 10 отдельно для токена и для проекта и общая. Токен: можно ли его продать, кто запустил и что стало с прошлыми монетами автора, кто из крупных держателей получил монеты прямо от автора, сколько реально вернёшь при продаже на $500. Проект: аудит, команда, инвесторы, документация, разработка на GitHub, соцсети, работающий продукт — каждый пункт со ссылкой на источник.',
hint: 'Оценка — это проверка рисков, а не совет. Решение за тобой.',
quota: function (q) {
if (q.owner) return '<b>Проверки без лимита</b> — доступ владельца.';
var s = q.left > 0 ? '<b>Лимит — ' + LIMIT + ' бесплатные проверки в день.</b> Сегодня осталось: <b>' + q.left + '</b>.' : '<b>Бесплатные проверки на сегодня закончились.</b> Обновятся в полночь по UTC.';
if (q.credits > 0) s += ' Купленных проверок: <b>' + q.credits + '</b>.';
else s += ' Дальше — 0,1 USDC за проверку.';
return s;
},
badAddr: 'Это не похоже на адрес токена (0x и ещё 40 символов).',
steps: { market: 'Ищу монету и её пулы', contract: 'Читаю контракт и пробую продать в симуляции', people: 'Смотрю автора, держателей и первых покупателей', project: 'Читаю про проект' },
notfound: 'Такой монеты нет ни на биржах, ни в обозревателе блоков Base и Robinhood Chain. Проверь адрес.',
dead: function (d) { return '🔴 НАДЁЖНОСТЬ 1/10 — ' + d.symbol + ' (' + d.name + ') существует в сети ' + (d.chain === 'base' ? 'Base' : 'Robinhood Chain') + ', но торговать ею негде: ни одного живого пула. Ликвидность выведена — монета мертва.'; },
chain: function (c) { return 'Монета торгуется в сети ' + c + '. Пока проверяю только Base и Robinhood Chain.'; },
trust: 'НАДЁЖНОСТЬ', labels: ['очень низкая — почти наверняка ловушка', 'низкая', 'средняя', 'высокая', 'очень высокая'],
scale: '10 — максимальное доверие, 1 — почти наверняка ловушка. Решение за тобой.',
lowers: 'Снижают надёжность', raises: 'Повышают надёжность',
market: 'Рынок', contract: 'Контракт и ликвидность', who: 'Кто запустил', holders: 'Держатели', project: 'Проект',
rightsTitle: 'Права команды — справка, не тревога',
rightsNote: 'У крупных проектов команда обычно оставляет себе управление, а среди крупнейших держателей — пулы, стейкинг и казна. Это вопрос доверия к команде, а не признак ловушки:',
base: 'Из новых монет на Base через две недели живёт примерно 1 из 50 (наш замер 23.09.2026). Это проверка рисков, а не совет покупать.',
share: 'Скопировать ссылку на отчёт', copied: 'Ссылка скопирована',
foot: 'Проверка идёт в твоём браузере по открытым данным: DexScreener, GoPlus, honeypot.is, GeckoTerminal, Blockscout, KyberSwap, CoinGecko. Разбор проекта пишет ИИ по источникам, которые он указывает. Код: <a href="https://github.com/araxis33/meme-scout" target="_blank" rel="noopener">github.com/araxis33/meme-scout</a>. Часть <a href="/">Base.tools</a>.',
projWait: 'Читаю про проект…', projOff: 'Разбор проекта сейчас недоступен — проверка по блокчейну выше полная.',
parts: function (tk, pj) { return 'Токен ' + tk + '/10 · ' + (pj === undefined ? 'проект: проверяю…' : pj === null ? 'проект не проверен — оценка только по токену' : 'Проект ' + pj + '/10'); },
pj: {
score: function (s, n) { return 'Проект ' + s + '/10 — найдено ' + n + ' из 9 критериев'; },
code: 'Код', team: 'Команда', dev: 'Разработка', community: 'Сообщество', product: 'Продукт', market: 'Рынок', spread: 'Распределение',
auditYes: function (by) { return 'Аудит' + (by ? ': ' + by : ' найден'); }, auditNo: 'Аудит в открытых источниках не найден',
srcOpen: 'Код контракта опубликован', srcHidden: 'Код контракта скрыт',
teamPublic: 'Команда публичная — имена известны', teamAnon: 'Команда сама называет себя анонимной', teamNo: 'Имена команды не найдены',
invYes: 'Есть инвесторы', invNo: 'Инвесторы не найдены',
docsYes: 'Документация', docsNo: 'Документация не найдена',
domain: function (date, d) { return 'Домен сайта зарегистрирован ' + date.split('-').reverse().join('.') + ' (' + (d >= 365 ? Math.floor(d / 365) + (Math.floor(d / 365) === 1 ? ' год' : Math.floor(d / 365) < 5 ? ' года' : ' лет') : Math.round(d / 30) + ' мес.') + ' назад)'; },
domainNo: 'Возраст домена сайта не определить', noSite: 'Сайт проекта не найден',
ghActive: function (n, repo) { return 'GitHub: ' + n + (n >= 100 ? '+' : '') + ' коммитов за 30 дней (' + repo + ')'; },
ghQuiet: function (date, repo) { return 'GitHub: последний коммит ' + date.split('-').reverse().join('.') + ' (' + repo + ')'; },
ghNo: 'GitHub не найден',
xYes: 'Аккаунт в X', xNo: 'Аккаунт в X не найден', chatYes: 'Telegram или Discord', chatNo: 'Telegram и Discord не найдены',
prodLive: 'Работающий продукт, которым можно пользоваться', prodNone: 'Продукта нет — только монета', prodNo: 'Работающий продукт не подтверждён',
marketLine: function (t) { return tierLine(t) || '—'; },
vest: function (p) { return 'в контрактах вестинга или блокировки: ' + p0(p); }, safe: function (p) { return 'в мультисигах команды: ' + p0(p); },
top10: function (p) { return '10 крупнейших кошельков (без бирж и контрактов): ' + p0(p); },
},
payTitle: 'Ещё проверки — 0,1 USDC за штуку',
payText: 'Оплата из твоего кошелька в сети Base. USDC уходят напрямую автору инструмента; купленные проверки не сгорают.',
pack: function (n) { return '<b>' + n + (n === 1 ? ' проверка' : n < 5 ? ' проверки' : ' проверок') + '</b>' + (n * 0.1).toFixed(1).replace('.', ',') + ' USDC'; },
noWallet: 'В этом браузере нет кошелька. Открой страницу в Coinbase Wallet или MetaMask или установи кошелёк.',
wait: 'Подтверди оплату в кошельке…', sent: 'Оплата отправлена — жду подтверждения сети Base…',
done: function (n, c) { return 'Оплачено. Добавлено проверок: ' + n + ', всего теперь: ' + c + '.'; },
lowUsdc: 'На этом кошельке недостаточно USDC в сети Base.', payFail: function (m) { return 'Оплата не прошла: ' + m; },
}
};
function pct(x) { return (Math.round(x * 10) / 10).toString() + '%'; }
function p0(x) { return Math.round(x) + '%'; }
function usd(x) { if (x === null || x === undefined) return '?'; if (x >= 1e9) return '$' + (x / 1e9).toFixed(1) + (lang === 'ru' ? ' млрд' : 'B'); if (x >= 1e6) return '$' + (x / 1e6).toFixed(1) + (lang === 'ru' ? ' млн' : 'M'); if (x >= 1e3) return '$' + Math.round(x / 1e3) + (lang === 'ru' ? ' тыс.' : 'K'); return '$' + Math.round(x); }
function tierLine(t) {
var ru = lang === 'ru', parts = [];
if (t.ageD >= 2) parts.push(Math.round(t.ageD) + (ru ? ' дн. торгов' : ' days of trading'));
if (t.holders) parts.push((ru ? 'держателей ' : 'holders ') + t.holders.toLocaleString(ru ? 'ru-RU' : 'en-US'));
if (t.cex) parts.push((ru ? 'на ' + t.cex + ' биржах' : 'on ' + t.cex + ' exchanges') + (t.majors.length ? (ru ? ', в т.ч. ' : ', incl. ') + t.majors.slice(0, 4).join(', ') : ''));
if (t.rank) parts.push((ru ? 'место #' : 'rank #') + t.rank + ' CoinGecko');
return parts.join(', ');
}
// Findings: [key, ...args] -> words.
var F = {
en: {
honeypot: function () { return 'cannot sell: it is a trap (honeypot)'; },
sellTaxHigh: function (t) { return 'sell tax ' + p0(t); }, sellTax: function (t) { return 'sell tax ' + p0(t); },
mint: function () { return 'the owner can mint more coins'; }, takeBack: function () { return 'the owner can take control back'; },
mintCapped: function (p, on) { return 'minting is capped by the code: at most ' + p + '% a year to the owner' + (on ? '' : ', not switched on yet'); },
hiddenRoles: function () { return 'the contract has hidden admin rights (roles outside the owner)'; },
rolesBalance: function () { return 'someone with rights can change balances'; }, rolesMint: function () { return 'someone with rights can mint'; },
blacklist: function () { return 'the owner can block a wallet'; }, taxChange: function () { return 'the owner can change the tax'; },
cannotSellAll: function () { return 'you cannot sell everything at once'; }, proxy: function () { return 'the code can be swapped (proxy)'; },
unverified: function () { return 'contract source is not published'; }, pause: function () { return 'the owner can stop trading'; },
personalTax: function () { return 'a tax can be set per wallet — a way to lock sellers in'; },
cooldown: function () { return 'there is a cooldown between trades'; }, antiWhale: function () { return 'the owner can change the trade size limit'; },
externalCall: function () { return 'the contract calls another contract — its behaviour can change'; },
creatorHoneypots: function () { return 'the same deployer has launched honeypots before'; },
lpPartUnlocked: function (s) { return 'LP of a v2 pool is not locked — ' + p0(s) + ' of all liquidity'; },
lpAtDev: function (p) { return 'the deployer holds the liquidity (' + p0(p) + ') — can pull it any time'; },
lpInContract: function (p) { return 'liquidity (' + p0(p) + ') sits in a contract — cannot tell if it is locked'; },
lpUnlocked: function (p) { return 'liquidity is not locked: ' + p0(p) + ' in a plain wallet — it can be pulled'; },
lpLocked: function (p) { return 'liquidity locked or burned (' + p0(p) + ')'; },
snipersHold: function (p) { return 'wallets that bought in the first seconds still hold ' + p0(p); },
creatorHolds: function (p) { return 'the deployer holds ' + p0(p) + ' of supply'; },
lowLiq: function (l) { return 'liquidity is only ' + usd(l); },
exitLoss: function (l) { return 'selling $500 loses ' + p0(l); },
exitOk: function (l) { return '$500 sells almost at no loss (' + pct(l) + ')'; },
top10: function (p) { return 'the 10 largest wallets (not exchanges or contracts) hold ' + p0(p); },
devToExchanges: function (p) { return 'the deployer sent ' + p0(p) + ' of supply to exchange wallets himself — done to make holders look solid'; },
fromDev: function (n, p) { return 'wallets that got coins straight from the deployer: ' + n + ', together ' + p0(p); },
cluster: function (n, p) { return 'wallets funded by one address: ' + n + ', together ' + p0(p); },
handed: function (n, p) { return 'wallets that got coins from one address: ' + n + ', together ' + p0(p); },
devFunded: function (n) { return 'the deployer funded ' + n + ' of the big holders himself'; },
serialDead: function (n, d) { return 'the deployer launched ' + n + ' coins, ' + d + ' are dead'; },
someDead: function (n, d) { return 'the deployer launched ' + n + ' coins, ' + d + ' are dead'; },
burner: function (m) { return 'the deployer wallet got its money ' + Math.round(m) + ' min before launch — a burner'; },
buyersMany: function (n) { return n + ' different buyers in 24h'; }, buyersFew: function (n) { return 'only ' + n + ' different buyers in 24h'; },
buysMany: function (n) { return n + ' buys in 24h'; }, buysFew: function (n) { return 'only ' + n + ' buys in 24h'; },
wash: function () { return 'volume is 20x+ the liquidity — looks like wash trading'; },
bots: function (x) { return Math.round(x) + ' buys per wallet on average — looks like bots'; },
young: function (h) { return 'the coin is ' + Math.round(h) + ' h old'; },
youngDays: function (dd) { return 'the coin is ' + Math.round(dd) + ' days old'; },
holdersUnknown: function () { return 'could not check how the coins are spread across holders'; },
noTrading: function (b, v, l) { return 'no trading: ' + b + ' buys and ' + usd(v) + ' volume in 24h against ' + usd(l) + ' liquidity — liquidity for show'; },
copy: function (s, a, l) { return 'looks like a copy: the real ' + s + ' is another address (' + CK.short(a) + ', liquidity ' + usd(l) + ') — check the address'; },
twin: function (s, a) { return 'there is a bigger ' + s + ' (' + CK.short(a) + ') — check the address'; },
mature: function (t) { return 'mature project: ' + tierLine(t); }, grown: function (t) { return 'no longer a newcomer: ' + tierLine(t); },
majors: function (m) { return 'trades on major exchanges: ' + m.slice(0, 4).join(', '); },
deep: function (u, more) { return 'a deep market: only a sale of ' + (more ? 'more than ' : '') + usd(u) + ' moves the price by 1%'; },
renounced: function () { return 'nobody controls the contract: the owner renounced it'; },
holdersMany: function (n) { return n.toLocaleString('en-US') + ' holders'; },
survived: function (dd) { return 'has traded for ' + Math.round(dd) + ' days'; },
},
ru: {
honeypot: function () { return 'продать нельзя: это ловушка (honeypot)'; },
sellTaxHigh: function (t) { return 'налог на продажу ' + p0(t); }, sellTax: function (t) { return 'налог на продажу ' + p0(t); },
mint: function () { return 'владелец может допечатать монеты'; }, takeBack: function () { return 'владелец может вернуть себе контроль'; },
mintCapped: function (p, on) { return 'допечатка ограничена кодом: не больше ' + String(p).replace('.', ',') + '% в год владельцу' + (on ? '' : ', пока не включена'); },
hiddenRoles: function () { return 'у контракта есть скрытые права управления (роли вне владельца)'; },
rolesBalance: function () { return 'кто-то с правами может менять балансы'; }, rolesMint: function () { return 'кто-то с правами может допечатать монеты'; },
blacklist: function () { return 'владелец может заблокировать кошелёк'; }, taxChange: function () { return 'владелец может поменять налог'; },
cannotSellAll: function () { return 'нельзя продать всё сразу'; }, proxy: function () { return 'код контракта можно подменить (прокси)'; },
unverified: function () { return 'код контракта не опубликован'; }, pause: function () { return 'владелец может остановить торговлю'; },
personalTax: function () { return 'налог можно задать отдельному кошельку — так запирают продавцов'; },
cooldown: function () { return 'есть пауза между сделками'; }, antiWhale: function () { return 'владелец может менять лимит на размер сделки'; },
externalCall: function () { return 'контракт обращается к чужому контракту — его поведение может поменяться'; },
creatorHoneypots: function () { return 'этот же автор уже выпускал монеты-ловушки'; },
lpPartUnlocked: function (s) { return 'доли пула v2 не заблокированы — это ' + p0(s) + ' всей ликвидности'; },
lpAtDev: function (p) { return 'ликвидность у автора (' + p0(p) + ') — может забрать в любой момент'; },
lpInContract: function (p) { return 'ликвидность (' + p0(p) + ') лежит в контракте — заблокирована ли, не видно'; },
lpUnlocked: function (p) { return 'ликвидность не заблокирована: ' + p0(p) + ' у обычного кошелька — может вывести'; },
lpLocked: function (p) { return 'ликвидность заблокирована или сожжена (' + p0(p) + ')'; },
snipersHold: function (p) { return 'кошельки, купившие в первые секунды, до сих пор держат ' + p0(p); },
creatorHolds: function (p) { return 'у автора ' + p0(p) + ' монет'; },
lowLiq: function (l) { return 'ликвидность всего ' + usd(l); },
exitLoss: function (l) { return 'при продаже на $500 теряешь ' + p0(l); },
exitOk: function (l) { return '$500 продаются почти без потерь (' + pct(l) + ')'; },
top10: function (p) { return '10 крупнейших кошельков (без бирж и контрактов) держат ' + p0(p); },
devToExchanges: function (p) { return 'автор сам отправил ' + p0(p) + ' монет на кошельки бирж — так делают, чтобы держатели выглядели солиднее'; },
fromDev: function (n, p) { return 'кошельков, получивших монеты прямо от автора: ' + n + ', вместе ' + p0(p); },
cluster: function (n, p) { return 'кошельков, получивших деньги с одного адреса: ' + n + ', вместе ' + p0(p); },
handed: function (n, p) { return 'кошельков, получивших монеты с одного адреса: ' + n + ', вместе ' + p0(p); },
devFunded: function (n) { return 'автор сам профинансировал крупных держателей: ' + n; },
serialDead: function (n, d) { return 'автор запускал монет: ' + n + ', мертвы ' + d; },
someDead: function (n, d) { return 'автор запускал монет: ' + n + ', мертвы ' + d; },
burner: function (m) { return 'кошелёк автора получил деньги за ' + Math.round(m) + ' мин до запуска — одноразовый'; },
buyersMany: function (n) { return n + ' разных покупателей за сутки'; }, buyersFew: function (n) { return 'всего ' + n + ' разных покупателей за сутки'; },
buysMany: function (n) { return n + ' покупок за сутки'; }, buysFew: function (n) { return 'всего ' + n + ' покупок за сутки'; },
wash: function () { return 'объём в 20+ раз больше ликвидности — похоже на накрутку'; },
bots: function (x) { return 'в среднем ' + Math.round(x) + ' покупок на кошелёк — похоже на ботов'; },
young: function (h) { return 'монете ' + Math.round(h) + ' ч'; },
youngDays: function (dd) { return 'монете ' + Math.round(dd) + ' дн.'; },
holdersUnknown: function () { return 'распределение монет между держателями проверить не удалось'; },
noTrading: function (b, v, l) { return 'торговли нет: за сутки покупок ' + b + ', объём ' + usd(v) + ' при ликвидности ' + usd(l) + ' — ликвидность для вида'; },
copy: function (s, a, l) { return 'похоже на копию: у настоящего ' + s + ' другой адрес (' + CK.short(a) + ', ликвидность ' + usd(l) + ') — сверь адрес'; },
twin: function (s, a) { return 'есть другая монета ' + s + ' крупнее (' + CK.short(a) + ') — сверь адрес'; },
mature: function (t) { return 'зрелый проект: ' + tierLine(t); }, grown: function (t) { return 'уже не новичок: ' + tierLine(t); },
majors: function (m) { return 'торгуется на крупных биржах: ' + m.slice(0, 4).join(', '); },
deep: function (u, more) { return 'рынок глубокий: цену на 1% сдвигает только продажа на ' + (more ? 'больше чем ' : '') + usd(u); },
renounced: function () { return 'контрактом никто не управляет: владелец от него отказался'; },
holdersMany: function (n) { return 'держателей ' + n.toLocaleString('ru-RU'); },
survived: function (dd) { return 'торгуется уже ' + Math.round(dd) + ' дн.'; },
}
};
function say(f) { return F[lang][f[0]].apply(null, f.slice(1)); }
function sayEn(f) { var keep = lang; lang = 'en'; var s = say(f); lang = keep; return s; }
var lang = 'en';
try { lang = localStorage.getItem('ck-lang') || ((navigator.language || '').toLowerCase().indexOf('ru') === 0 ? 'ru' : 'en'); } catch (e) {}
function store(k, v) { try { if (v === undefined) return localStorage.getItem(k); localStorage.setItem(k, v); } catch (e) {} return null; }
// A browser id: paid checks belong to it, so they survive a change of network.
var client = store('ck-client');
if (!client) { client = (crypto.randomUUID ? crypto.randomUUID() : String(Math.random()).slice(2) + Date.now().toString(16)).replace(/[^a-f0-9-]/gi, ''); store('ck-client', client); }
// Owner access: opened once as check.html?owner=KEY, remembered in this browser.
var params = new URLSearchParams(location.search);
if (params.get('owner')) { store('ck-owner', params.get('owner')); history.replaceState(null, '', location.pathname + (params.get('a') ? '?a=' + params.get('a') : '')); }
var ownerKey = store('ck-owner');
function hdr(extra) { var h = { 'x-client': client }; if (ownerKey) h['x-owner'] = ownerKey; for (var k in extra || {}) h[k] = extra[k]; return h; }
var q = { left: LIMIT, credits: 0, owner: false }, workerUp = false, last = null;
function el(tag, cls, text) { var e = document.createElement(tag); if (cls) e.className = cls; if (text !== undefined) e.textContent = text; return e; }
function $(id) { return document.getElementById(id); }
function paintStatic() {
var t = T[lang];
document.documentElement.lang = lang;
$('t-title').textContent = t.title; $('t-sub').textContent = t.sub; $('t-hint').textContent = t.hint;
$('go').textContent = t.go; $('t-foot').innerHTML = t.foot;
$('l-en').className = lang === 'en' ? 'on' : ''; $('l-ru').className = lang === 'ru' ? 'on' : '';
$('quota').innerHTML = t.quota(q);
if (!$('pay').hidden) paintPay();
if (last) render(last.d, last.a, last.project);
}
function setLang(l) { lang = l; store('ck-lang', l); paintStatic(); }
$('l-en').onclick = function () { setLang('en'); };
$('l-ru').onclick = function () { setLang('ru'); };
// ---- the limit: the Worker counts; a local counter is the fallback
function today() { return new Date().toISOString().slice(0, 10); }
function localLeft() { try { var s = JSON.parse(store('ck-quota') || '{}'); return s.day === today() ? Math.max(0, LIMIT - s.used) : LIMIT; } catch (e) { return LIMIT; } }
function localUse() { try { var s = JSON.parse(store('ck-quota') || '{}'); if (s.day !== today()) s = { day: today(), used: 0 }; s.used++; store('ck-quota', JSON.stringify(s)); } catch (e) {} }
function refreshQuota() {
q = { left: localLeft(), credits: 0, owner: false };
return fetch(WORKER + '/quota', { headers: hdr() }).then(function (r) { return r.json(); })
.then(function (x) { workerUp = true; q = x; paintStatic(); })
.catch(function () { workerUp = false; paintStatic(); });
}
function takeTicket() {
if (!workerUp) { if (localLeft() <= 0) return Promise.resolve(null); localUse(); q.left = localLeft(); return Promise.resolve('local'); }
return fetch(WORKER + '/start', { method: 'POST', headers: hdr() }).then(function (r) { return r.json(); })
.then(function (x) { q.left = x.left; q.credits = x.credits || 0; q.owner = !!x.owner; return x.ok ? x.ticket : null; })
.catch(function () { workerUp = false; return takeTicket(); });
}
// ---- paying for more checks
var payState = { text: '', cls: '' };
function paintPay() {
var t = T[lang], box = $('pay');
box.innerHTML = '';
box.appendChild(el('h2', null, t.payTitle));
box.appendChild(el('p', null, t.payText));
var packs = el('div', 'packs');
PACKS.forEach(function (n) { var b = el('button'); b.type = 'button'; b.innerHTML = t.pack(n); b.onclick = function () { buy(n); }; packs.appendChild(b); });
box.appendChild(packs);
box.appendChild(el('div', 'paystat ' + payState.cls, payState.text));
}
function showPay() { $('pay').hidden = false; paintPay(); $('pay').scrollIntoView({ behavior: 'smooth', block: 'center' }); }
function payStatus(text, cls) { payState = { text: text, cls: cls || '' }; paintPay(); }
function pad(hex) { return hex.replace(/^0x/, '').toLowerCase().padStart(64, '0'); }
function wallet() { return window.ethereum || window.coinbaseWalletExtension || null; }
function sleep(ms) { return new Promise(function (r) { setTimeout(r, ms); }); }
function lockPacks(on) { Array.prototype.forEach.call(document.querySelectorAll('.packs button'), function (b) { b.disabled = on; }); }
function buy(n) {
var t = T[lang], p = wallet();
if (!p) { payStatus(t.noWallet, 'bad'); return; }
var from, amount = BigInt(n) * 100000n;
lockPacks(true);
p.request({ method: 'eth_requestAccounts' }).then(function (acc) {
from = acc[0];
return p.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0x2105' }] }).catch(function (e) {
if (e && e.code === 4902) return p.request({ method: 'wallet_addEthereumChain', params: [{ chainId: '0x2105', chainName: 'Base', nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 }, rpcUrls: ['https://mainnet.base.org'], blockExplorerUrls: ['https://basescan.org'] }] });
throw e;
});
}).then(function () {
return p.request({ method: 'eth_call', params: [{ to: USDC, data: '0x70a08231' + pad(from) }, 'latest'] });
}).then(function (bal) {
if (BigInt(bal || '0x0') < amount) throw new Error(t.lowUsdc);
payStatus(t.wait);
// transfer(PAY_TO, amount) + builder code: contracts ignore the tail, Base's indexer reads it.
var data = '0xa9059cbb' + pad(PAY_TO) + pad(amount.toString(16)) + BUILDER_SUFFIX;
return p.request({ method: 'eth_sendTransaction', params: [{ from: from, to: USDC, data: data, value: '0x0' }] });
}).then(function (tx) {
payStatus(t.sent);
store('ck-pending-tx', tx); // kept until credited: a paid check must never be lost
return confirmPayment(tx);
}).catch(function (e) {
payStatus(t.payFail((e && (e.message || e.reason)) || String(e)), 'bad');
}).then(function () { lockPacks(false); });
}
// Ask the Worker to credit a sent payment, retrying while it is not mined yet
// or a node hiccups. On 23.09.2026 a real payment went through on chain but the
// Worker's node refused, and the check was only credited by hand.
function confirmPayment(tx) {
var t = T[lang], tries = 0;
function poll() {
tries++;
return fetch(WORKER + '/pay', { method: 'POST', headers: hdr({ 'content-type': 'application/json' }), body: JSON.stringify({ tx: tx }) })
.then(function (r) { return r.json(); }, function () { return { pending: true }; }).then(function (x) {
if (x.ok || x.error === 'used') { store('ck-pending-tx', ''); q.credits = x.credits || q.credits; paintStatic(); if (x.ok) payStatus(t.done(x.added, x.credits), 'ok'); return; }
if ((x.pending || /blockscout|node|rpc|fetch|429|5\d\d/i.test(x.error || '')) && tries < 45) return sleep(4000).then(poll);
if (/no payment|too old|failed tx|bad tx/.test(x.error || '')) store('ck-pending-tx', '');
throw new Error(x.error || 'not confirmed');
});
}
return poll();
}
// ---- steps
var STEP_ORDER = ['market', 'contract', 'people', 'project'];
function showStep(k) {
var box = $('steps'); box.innerHTML = '';
var reached = true;
STEP_ORDER.forEach(function (s) {
var cls = s === k ? 'step now' : reached ? 'step done' : 'step';
if (s === k) reached = false;
box.appendChild(el('div', cls, (cls === 'step done' ? '✓ ' : '• ') + T[lang].steps[s]));
});
}
// ---- the standard scanner table
function checklist(d, a) {
var ru = lang === 'ru', gp = d.gp, hp = d.hp, rows = [];
var yes = function (k) { return String(gp[k]) === '1'; }, known = function (k) { return gp[k] !== undefined && gp[k] !== null && gp[k] !== ''; };
var owner = (gp.owner_address || '').toLowerCase(), renounced = !owner || CK.BURN.has(owner);
var hr = hp.honeypotResult || {}, sim = hp.simulationResult || {};
if (hp.honeypotResult || known('is_honeypot')) {
var trap = hr.isHoneypot || yes('is_honeypot');
rows.push((trap ? '❌ ' : '✅ ') + (ru ? (trap ? 'Продать нельзя (ловушка)' : 'Продать можно — продажа проходит в симуляции') : (trap ? 'Cannot sell (trap)' : 'Sellable — a sale passes in simulation')));
} else rows.push('➖ ' + (ru ? 'Проверка продажи для этой сети недоступна' : 'Sell check is not available for this chain'));
var bt = sim.buyTax, st = sim.sellTax;
if (bt === undefined && known('buy_tax')) bt = parseFloat(gp.buy_tax) * 100;
if (st === undefined && known('sell_tax')) st = parseFloat(gp.sell_tax) * 100;
if (bt !== undefined || st !== undefined) {
var hi = (bt || 0) > 5 || (st || 0) > 5;
rows.push((hi ? '❌ ' : '✅ ') + (ru ? 'Налог: покупка ' : 'Tax: buy ') + Math.round(bt || 0) + (ru ? '%, продажа ' : '%, sell ') + Math.round(st || 0) + '%');
}
if (Object.keys(gp).length) {
rows.push((renounced ? '✅ ' : '⚠️ ') + (ru ? (renounced ? 'Владелец отказался от контракта' : 'Владелец на месте: ' + CK.short(owner)) : (renounced ? 'Owner renounced' : 'Owner present: ' + CK.short(owner))));
var pairs = [['is_mintable', 'допечатка монет', 'minting'], ['is_blacklisted', 'блокировка кошельков', 'wallet blacklist'],
['transfer_pausable', 'остановка торговли', 'trading pause'], ['slippage_modifiable', 'смена налога', 'tax change'],
['personal_slippage_modifiable', 'налог отдельному кошельку', 'per-wallet tax'], ['can_take_back_ownership', 'возврат владения', 'ownership take-back'],
['hidden_owner', 'скрытый владелец', 'hidden owner'], ['is_proxy', 'подмена кода (прокси)', 'code swap (proxy)'],
['selfdestruct', 'самоуничтожение контракта', 'self-destruct'], ['is_anti_whale', 'лимит на размер сделки', 'trade size limit'],
['trading_cooldown', 'пауза между сделками', 'trade cooldown']];
var present = pairs.filter(function (p) { return yes(p[0]) && !(p[0] === 'is_mintable' && d.mintCap); }).map(function (p) { return ru ? p[1] : p[2]; });
if (d.mintCap) rows.push('➖ ' + (ru ? 'Допечатка ограничена кодом Doppler: не больше ' + String(d.mintCap.pct).replace('.', ',') + '% в год' + (d.mintCap.started ? '' : ', пока не включена') : 'Minting capped by the Doppler code: at most ' + d.mintCap.pct + '% a year' + (d.mintCap.started ? '' : ', not switched on yet')));
var absent = pairs.filter(function (p) { return known(p[0]) && !yes(p[0]); }).map(function (p) { return ru ? p[1] : p[2]; });
if (present.length) rows.push('⚠️ ' + (ru ? 'Есть в коде: ' : 'In the code: ') + present.join(', ') + (renounced && !yes('hidden_owner') ? (ru ? ' (но владелец отказался)' : ' (but the owner renounced)') : ''));
if (absent.length) rows.push('✅ ' + (ru ? 'Нет в коде: ' : 'Not in the code: ') + absent.join(', '));
var open = gp.is_open_source === '1';
rows.push((open ? '✅ ' : '❌ ') + (ru ? (open ? 'Код контракта опубликован' : 'Код контракта скрыт') : (open ? 'Source published' : 'Source hidden')));
if (yes('honeypot_with_same_creator')) rows.push('❌ ' + (ru ? 'Автор уже выпускал монеты-ловушки' : 'The deployer has launched honeypots before'));
} else rows.push('➖ ' + (ru ? 'Разбор кода контракта для этой сети недоступен' : 'Contract code check is not available for this chain'));
var lp = a.lp;
if (lp.v2 && lp.lockedPct !== null && lp.share < 10) rows.push('➖ ' + (ru ? 'Блокировка ликвидности: сканеры видят только малый пул v2 (' + p0(lp.share) + ' ликвидности), по основным пулам не проверить' : 'Liquidity lock: scanners only see a small v2 pool (' + p0(lp.share) + ' of liquidity); the main pools cannot be checked'));
else if (lp.v2 && lp.lockedPct !== null) {
if (lp.lockedPct >= 90) rows.push('✅ ' + (ru ? 'Ликвидность заблокирована или сожжена: ' : 'Liquidity locked or burned: ') + p0(lp.lockedPct));
else {
var who = lp.top ? (lp.top.addr === (d.dev.dev || '') ? (ru ? ' — у автора' : ' — held by the deployer') : lp.top.contract ? (ru ? ' — в контракте ' : ' — in contract ') + CK.short(lp.top.addr) : (ru ? ' — у кошелька ' : ' — in wallet ') + CK.short(lp.top.addr)) : '';
var part = lp.share >= 90 ? '' : (ru ? ' (пул v2 — ' + p0(lp.share) + ' всей ликвидности)' : ' (a v2 pool — ' + p0(lp.share) + ' of liquidity)');
rows.push((lp.share >= 50 ? '❌ ' : '⚠️ ') + (ru ? 'Ликвидность заблокирована на ' : 'Liquidity locked: ') + p0(lp.lockedPct) + (ru ? ', свободно ' : ', free ') + p0(lp.top ? lp.top.pct : 0) + who + part);
}
} else if (lp.onlyV3V4) rows.push('➖ ' + (ru ? 'Ликвидность в пулах Uniswap v3/v4 — блокировку там не проверить; следи за её падением' : 'Liquidity is in Uniswap v3/v4 pools — locks cannot be checked there; watch for it dropping'));
if (known('creator_percent')) { var cp = parseFloat(gp.creator_percent) * 100; rows.push((cp <= 5 ? '✅ ' : '❌ ') + (ru ? 'У автора сейчас ' : 'Deployer holds now: ') + pct(cp)); }
var sn = d.snipe;
if (sn && sn.found) rows.push((sn.stillPct > 15 ? '❌ ' : sn.early >= 10 ? '⚠️ ' : '✅ ') + (ru ? 'Снайперы — кошельки, скупившие монету в первые ~6 с после запуска (боты или свои): ' : 'Snipers — wallets that bought in the first ~6 s after launch (bots or insiders): ') + sn.early + (sn.sameBlock > 1 ? (ru ? ', из них ' + sn.sameBlock + ' в самом первом блоке' : ', ' + sn.sameBlock + ' in the very first block') : '') + (ru ? '. Сейчас у них ' : '. They hold now ') + pct(sn.stillPct) + ' — ' + (sn.stillPct > 15 ? (ru ? 'могут разом продать и обвалить цену' : 'they can dump at once and crash the price') : sn.stillPct < 3 ? (ru ? 'угрозы сброса почти нет' : 'little risk of a dump') : (ru ? 'следи, не начнут ли продавать' : 'watch whether they start selling')));
else if (sn && !sn.found) rows.push('✅ ' + (ru ? 'Снайперов на старте не видно' : 'No snipers seen at launch'));
return rows;
}
function card(title, cls) { var s = el('section', 'card' + (cls ? ' ' + cls : '')); s.appendChild(el('h2', null, title)); return s; }
function line(parent, text, cls) { parent.appendChild(el('p', cls, text)); }
function band(tr) { return tr <= 2 ? 0 : tr <= 4 ? 1 : tr <= 6 ? 2 : tr <= 8 ? 3 : 4; }
function render(d, a, project) {
var t = T[lang], ru = lang === 'ru', out = $('out');
out.innerHTML = '';
if (d.error) { out.appendChild(el('div', 'err', d.error === 'chain' ? t.chain(d.chain) : d.error === 'dead' ? t.dead(d) : t.notfound)); return; }
var r = el('div', 'report');
var head = el('div', 'head');
head.appendChild(el('span', 'sym', d.symbol)); head.appendChild(el('span', 'nm', d.name + ' · ' + (d.chain === 'base' ? 'Base' : 'Robinhood Chain')));
r.appendChild(head); r.appendChild(el('div', 'addr', d.address));
// The headline is the overall score once the project is read; until then, the token's.
var ps = project && project.checks ? CK.projectScore(project.checks) : null;
var total = CK.overall(a, ps);
var b = band(total);
var sc = el('div', 'score t' + Math.min(4, b + 1), ['🔴', '🟠', '🟡', '🟢', '🟢'][b] + ' ' + t.trust + ' ' + total + '/10 — ' + t.labels[b]);
var bar = el('div', 'bar'); bar.style.color = ['var(--red)', 'var(--orange)', 'var(--yellow)', 'var(--green)', 'var(--green)'][b];
for (var i = 1; i <= 10; i++) bar.appendChild(el('i', i <= total ? 'on' : ''));
sc.appendChild(bar); r.appendChild(sc);
r.appendChild(el('p', 'parts', t.parts(a.trust, project === undefined ? undefined : ps ? ps.score : null)));
r.appendChild(el('p', 'scale', t.scale));
if (a.hard.length || a.up.length) {
r.appendChild(el('h3', null, t.lowers));
var u1 = el('ul', 'find');
a.hard.forEach(function (f) { u1.appendChild(el('li', null, '⛔ ' + say(f))); });
a.up.forEach(function (f) { u1.appendChild(el('li', null, '⚠️ ' + say(f))); });
r.appendChild(u1);
}
// Age and holders are already in the "no longer a newcomer" line: no need to repeat them.
var downs = a.tier.level === 'new' ? a.down : a.down.filter(function (f) { return f[0] !== 'holdersMany' && f[0] !== 'survived'; });
if (downs.length) {
r.appendChild(el('h3', null, t.raises));
var u2 = el('ul', 'find');
downs.forEach(function (f) { u2.appendChild(el('li', null, '✅ ' + say(f))); });
r.appendChild(u2);
}
if (a.rights.length) {
var rc = card(t.rightsTitle, 'rights'); line(rc, t.rightsNote, 'note');
a.rights.forEach(function (f) { line(rc, '• ' + say(f)); }); r.appendChild(rc);
}
var ageTxt = d.ageH >= 48 ? Math.round(d.ageH / 24) + (ru ? ' дн.' : ' days') : Math.round(d.ageH || 0) + (ru ? ' ч' : ' h');
var m = card(t.market);
line(m, (ru ? 'Капа ' : 'Market cap ') + usd(d.mcap) + (ru ? ' · ликвидность ' : ' · liquidity ') + usd(d.liq) + (ru ? ' · объём за сутки ' : ' · 24h volume ') + usd(d.vol));
line(m, (ru ? 'Возраст ' : 'Age ') + ageTxt + (ru ? ' · пулов ' : ' · pools ') + d.pools + (ru ? ' · держателей ' : ' · holders ') + (d.holderCount ? d.holderCount.toLocaleString(ru ? 'ru-RU' : 'en-US') : '?'));
if (d.buyers !== null) line(m, (ru ? 'За сутки: ' : '24h: ') + d.buyers + (ru ? ' покупателей, ' : ' buyers, ') + d.sellers + (ru ? ' продавцов' : ' sellers'));
else line(m, (ru ? 'За сутки: ' : '24h: ') + d.dsBuys + (ru ? ' покупок, ' : ' buys, ') + d.dsSells + (ru ? ' продаж' : ' sells'));
var trapSale = a.hard.some(function (f) { return f[0] === 'honeypot'; });
if (Object.keys(d.exits).length) {
if (trapSale) line(m, ru ? 'Маршрут обмена обещает выкуп, но симуляция продажи падает — этим цифрам не верь' : 'The swap route quotes a price, but the sell simulation fails — do not trust these numbers');
else line(m, (ru ? 'Продать сейчас: ' : 'Sell now: ') + Object.keys(d.exits).map(function (k) { return '$' + Number(k).toLocaleString('en-US') + ' → $' + Math.round(d.exits[k][1]).toLocaleString('en-US'); }).join(' · '));
}
// Two market facts borrowed from Blocktronics V2's pillars: liquidity depth and the last 30 days.
if (d.depth && !trapSale) line(m, d.depth.below
? (ru ? 'Глубина: уже продажа на $1 000 сдвигает цену больше чем на 1%' : 'Depth: even a $1,000 sale moves the price by more than 1%')
: (ru ? 'Глубина: цену на 1% сдвигает продажа на ' : 'Depth: a sale that moves the price by 1%: ') + (d.depth.atLeast ? (ru ? 'больше чем ' : 'more than ') : '') + usd(d.depth.usd) + (ru ? ' (без учёта комиссии пула)' : ' (pool fees aside)'));
if (d.month) {
var mo = d.month, ch = mo.change === null ? '' : (mo.change >= 0 ? '+' : '') + Math.round(mo.change) + '%';
line(m, ru ? '30 дней: дней роста ' + mo.up + ' из ' + mo.days + (ch ? ', цена ' + ch : '') + ', средний объём ' + usd(mo.vol) + ' в день'
: '30 days: ' + mo.up + ' up days of ' + mo.days + (ch ? ', price ' + ch : '') + ', average volume ' + usd(mo.vol) + ' a day');
}
r.appendChild(m);
var c = card(t.contract); checklist(d, a).forEach(function (s) { line(c, s); }); r.appendChild(c);
var w = card(t.who), dv = d.dev || {};
if (dv.dev) {
line(w, (ru ? 'Автор ' : 'Deployer ') + CK.short(dv.dev));
if (dv.funder) {
var mins = dv.fundedBeforeMin, when = '';
if (mins !== null && mins !== undefined) when = mins < 120 ? (ru ? ', за ' + Math.round(mins) + ' мин до запуска' : ', ' + Math.round(mins) + ' min before launch') : mins < 2880 ? (ru ? ', за ' + Math.round(mins / 60) + ' ч до запуска' : ', ' + Math.round(mins / 60) + ' h before launch') : (ru ? ', за ' + Math.round(mins / 1440) + ' дн. до запуска' : ', ' + Math.round(mins / 1440) + ' days before launch');
line(w, (ru ? 'Первые деньги: ' : 'First money from: ') + CK.short(dv.funder) + (dv.funderLabel ? ' (' + (dv.funderLabel === 'exchange' ? (ru ? 'биржа или мост' : 'exchange or bridge') : dv.funderLabel) + ')' : '') + (dv.funderAmount ? ' ' + dv.funderAmount.toFixed(4) + ' ETH' : '') + when);
}
if (dv.devHistoryComplete === false && !dv.funder) line(w, ru ? 'Кошелёк давний и активный: больше ' + (dv.devTxCount || 150) + ' операций — не одноразовый' : 'An old, active wallet: more than ' + (dv.devTxCount || 150) + ' transactions — not a burner');
var L = dv.launches || [];
if (L.length) { var alive = L.filter(function (l) { return l.liq >= 1000; }); line(w, (ru ? 'Другие его монеты: ' : 'His other coins: ') + L.length + (ru ? ', живы ' : ', alive ') + alive.length + (alive.length ? ' (' + alive.sort(function (x, y) { return y.liq - x.liq; }).slice(0, 4).map(function (l) { return l.symbol + ' ' + usd(l.liq); }).join(', ') + ')' : '')); }
else line(w, ru ? 'Других запусков с этого кошелька не видно' : 'No other launches from this wallet');
} else line(w, ru ? 'Автора определить не удалось' : 'Could not identify the deployer');
r.appendChild(w);
var h = card(t.holders);
d.holders.rows.slice(0, 6).forEach(function (row) {
var tag = { pool: ru ? 'пул' : 'pool', burn: ru ? 'сожжено' : 'burned', contract: ru ? 'контракт' : 'contract' }[row.kind] || '';
if (row.kind === 'contract' && row.name) tag += ' ' + row.name;
if (row.isDev) tag = ru ? 'автор' : 'deployer';
else if (row.gotFrom && row.gotFrom === dv.dev) tag = row.exchange ? (ru ? 'биржа, получила от автора' : 'exchange, got it from the deployer') : (ru ? 'получил от автора' : 'got it from the deployer');
else if (row.exchange) tag = ru ? 'биржа' : 'exchange';
else if (row.gotFrom === 'pool') tag = ru ? 'купил' : 'bought';
line(h, pct(row.pct) + ' ' + CK.short(row.address) + ' ' + tag);
});
d.holders.clusters.slice(0, 2).forEach(function (cl) { line(h, '🔗 ' + (ru ? 'кошельков с деньгами от ' : 'wallets funded by ') + CK.short(cl[0]) + ': ' + cl[1].length + (ru ? ', вместе ' : ', together ') + p0(cl[1].reduce(function (s, x) { return s + x.pct; }, 0))); });
r.appendChild(h);
var p = card(t.project, 'proj');
if (project === undefined) line(p, t.projWait, 'note');
else if (!project) line(p, t.projOff, 'note');
else {
if (ps) {
line(p, t.pj.score(ps.score, Object.keys(ps.items).filter(function (k) { return ps.items[k] > 0; }).length), 'pscore');
projectRows(d, project.checks, a).forEach(function (g) {
p.appendChild(el('h3', 'pgroup', g[0]));
g[1].forEach(function (row) {
var e = el('p', null, row[0] + ' ' + row[1]);
if (row[2]) { var lk = el('a', null, ' ↗'); lk.href = row[2]; lk.target = '_blank'; lk.rel = 'noopener nofollow'; e.appendChild(lk); }
p.appendChild(e);
});
});
}
if (project.text) line(p, project.text, 'ptext');
if (project.sources && project.sources.length) {
var src = el('p', 'note'); src.appendChild(document.createTextNode(ru ? 'Источники: ' : 'Sources: '));
project.sources.forEach(function (s, i) { var aEl = el('a', null, '[' + s.n + ']'); aEl.href = s.url; aEl.target = '_blank'; aEl.rel = 'noopener nofollow'; if (i) src.appendChild(document.createTextNode(' · ')); src.appendChild(aEl); });
p.appendChild(src);
}
if (project.note) line(p, project.note, 'note');
}
r.appendChild(p);
var sh = el('button', 'share', t.share); sh.type = 'button';
sh.onclick = function () {
var link = location.origin + location.pathname + '?a=' + d.address;
(navigator.clipboard ? navigator.clipboard.writeText(link) : Promise.reject()).then(function () { sh.textContent = t.copied; }, function () { window.prompt('', link); });
};
r.appendChild(sh);
r.appendChild(el('p', 'note', t.base));
if (d.url) { var links = el('p', 'note'); var g = el('a', null, ru ? 'График' : 'Chart'); g.href = d.url; g.target = '_blank'; g.rel = 'noopener'; links.appendChild(g); r.appendChild(links); }
out.appendChild(r);
}
// The project's criteria, grouped as in CertiK Skynet's pillars: [title, [[icon, text, link]]].
function projectRows(d, pc, a) {
var pj = T[lang].pj, gp = d.gp, gh = pc.github, rows = [];
var days = function (iso) { return iso ? (Date.now() - Date.parse(iso)) / 86400000 : null; };
var code = [pc.audit === 'yes' ? ['✅', pj.auditYes(pc.auditBy), pc.auditUrl] : ['➖', pj.auditNo]];
if (gp.is_open_source !== undefined) code.push(gp.is_open_source === '1' ? ['✅', pj.srcOpen] : ['❌', pj.srcHidden]);
rows.push([pj.code, code]);
var dom = days(pc.domainSince);
rows.push([pj.team, [
pc.team === 'public' ? ['✅', pj.teamPublic, pc.teamUrl] : pc.team === 'anon' ? ['⚠️', pj.teamAnon] : ['➖', pj.teamNo],
pc.investors === 'yes' ? ['✅', pj.invYes, pc.investorsUrl] : ['➖', pj.invNo],
pc.docs ? ['✅', pj.docsYes, pc.docs] : ['➖', pj.docsNo],
!pc.site ? ['➖', pj.noSite] : dom === null ? ['➖', pj.domainNo, pc.site] : [dom >= 365 ? '✅' : dom >= 90 ? '➖' : '⚠️', pj.domain(pc.domainSince, dom), pc.site],
]]);
var push = gh ? days(gh.pushed) : null, repo = gh ? gh.url.replace('https://github.com/', '') : '';
rows.push([pj.dev, [!gh ? ['➖', pj.ghNo] : gh.commits30 > 0 ? ['✅', pj.ghActive(gh.commits30, repo), gh.url]
: [push !== null && push <= 180 ? '➖' : '⚠️', pj.ghQuiet(gh.pushed, repo), gh.url]]]);
rows.push([pj.community, [pc.x ? ['✅', pj.xYes, pc.x] : ['➖', pj.xNo], pc.chat ? ['✅', pj.chatYes, pc.chat] : ['➖', pj.chatNo]]]);
rows.push([pj.product, [pc.product === 'live' ? ['✅', pj.prodLive, pc.productUrl] : pc.product === 'none' ? ['⚠️', pj.prodNone] : ['➖', pj.prodNo]]]);
// On-chain facts the token score already weighs: shown here so the picture is whole.
rows.push([pj.market, [['•', pj.marketLine(a.tier)]]]);
var hr = d.holders.rows, sum = function (re) { return hr.filter(function (x) { return x.kind === 'contract' && re.test(x.name || ''); }).reduce(function (s, x) { return s + x.pct; }, 0); };
var vest = sum(/vest|lock|timelock/i), safe = sum(/safe|multisig/i);
var top10 = hr.filter(function (x) { return x.kind === 'wallet' && !x.exchange; }).slice(0, 10).reduce(function (s, x) { return s + x.pct; }, 0);
var spread = [];
if (vest >= 1) spread.push(['•', pj.vest(vest)]);
if (safe >= 1) spread.push(['•', pj.safe(safe)]);
if (hr.length) spread.push(['•', pj.top10(top10)]);
if (spread.length) rows.push([pj.spread, spread]);
return rows;
}
function facts(d, a) {
return { symbol: d.symbol, name: d.name, chain: d.chain, address: d.address, websites: d.websites, socials: d.socials,
trust: a.trust, verdict: 'TRUST ' + a.trust + '/10', stop: a.hard.map(sayEn), warn: a.up.map(sayEn), good: a.down.map(sayEn), rights: a.rights.map(sayEn),
mcap: d.mcap, liq: d.liq, vol: d.vol, ageH: d.ageH, buyers: d.buyers, sellers: d.sellers, dsBuys: d.dsBuys, dsSells: d.dsSells,
cg: { name: d.cg.name, id: d.cg.id, updated: d.cg.updated, categories: d.cg.categories, genesis: d.cg.genesis,
description: d.cg.description, homepage: d.cg.homepage, repos: d.cg.repos, cex: (d.cg.cex || []).length,
twitter: d.cg.twitter, telegram: d.cg.telegram, chats: d.cg.chats, whitepaper: d.cg.whitepaper } };
}
function run() {
var m = CK.ADDR_RE.exec($('addr').value || '');
$('out').innerHTML = '';
if (!m) { $('out').appendChild(el('div', 'err', T[lang].badAddr)); return; }
$('go').disabled = true;
takeTicket().then(function (ticket) {
paintStatic();
if (!ticket) { $('go').disabled = false; showPay(); return; }
CK.collect(m[0], showStep).then(function (d) {
if (d.error) { $('steps').innerHTML = ''; last = null; render(d); $('go').disabled = false; return; }
var a = CK.assess(d);
last = { d: d, a: a, project: undefined };
showStep('project'); render(d, a, undefined);
var proj = ticket === 'local' ? Promise.resolve(null) :
fetch(WORKER + '/read', { method: 'POST', headers: hdr({ 'content-type': 'application/json' }), body: JSON.stringify({ ticket: ticket, lang: lang, facts: facts(d, a) }) })
.then(function (r) { return r.ok ? r.json() : null; }).catch(function () { return null; });
proj.then(function (pr) {
last.project = pr && (pr.text || pr.checks) ? pr : null;
$('steps').innerHTML = ''; render(d, a, last.project); $('go').disabled = false;
});
}).catch(function (e) {
$('steps').innerHTML = ''; $('out').appendChild(el('div', 'err', String(e && e.message || e))); $('go').disabled = false;
});
});
}
$('f').onsubmit = function (ev) { ev.preventDefault(); run(); };
if (params.get('a')) $('addr').value = params.get('a');
paintStatic();
refreshQuota().then(function () {
var pend = store('ck-pending-tx');
if (pend) confirmPayment(pend).catch(function () {});
if (params.get('a') && params.get('go') === '1') run();
});
})();
</script>
<!-- Cloudflare Web Analytics: page views only, no cookies --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "d66a3ce27f4e4b47bb1eb31a0e5fa912"}'></script>
</body>
</html>