Ethscriptions commited on
Commit
516d3e1
·
1 Parent(s): 669f27d

Add application file

Browse files
app.py ADDED
@@ -0,0 +1,1506 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import re
4
+ import json
5
+ import hashlib
6
+ import pandas as pd
7
+ import base64
8
+ import sqlite3
9
+ import os
10
+
11
+ infura_api_key = "9bbc614b8a1d49d59869e97d0ee3bf61"
12
+
13
+ # Ethscriptions Mainnet API 的基础 URL
14
+ BASE_URL = "https://mainnet-api.ethscriptions.com/api"
15
+
16
+ # 获取当前文件目录
17
+ current_dir = os.path.dirname(os.path.abspath(__file__))
18
+
19
+ # 构造数据库文件路径
20
+ eths_db_file = os.path.join(current_dir, 'data', 'eths_data.db')
21
+
22
+ # Initialize connection to SQLite database
23
+ conn = sqlite3.connect(eths_db_file)
24
+ c = conn.cursor()
25
+
26
+ # Create table to store ETHS data
27
+ c.execute('''
28
+ CREATE TABLE IF NOT EXISTS eths_data
29
+ (date text,
30
+ eth_price real,
31
+ eths_price real,
32
+ eths_market_cap integer,
33
+ eths_owners integer,
34
+ eths_volume24h real,
35
+ eths_totalLocked integer,
36
+ eths_stakers integer,
37
+ eths_tvl real)
38
+ ''')
39
+
40
+ # 查询地址所属代币铭文的 token 列表
41
+ token_list = [{'p': 'erc-20', 'tick': 'eths', 'id': 21000, 'amt': '1000'},
42
+ {'p': 'erc-20', 'tick': 'gwei', 'id': 21000, 'amt': '1000'},
43
+ {'p': 'erc-20', 'tick': 'ercs', 'id': 21000, 'amt': '1000'},
44
+ {'p': 'erc-20', 'tick': 'etch', 'id': 21000, 'amt': '1000'},
45
+ {'p': 'erc-20', 'tick': 'dumb', 'id': 21000, 'amt': '1000'}]
46
+
47
+ ethscrptions_logo = """<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="-0.53 -2.18 14.000028839170737 20.067148724063962" style="enable-background:new 0 0 100 16.4081;" xml:space="preserve" width="19" height="25" xmlns:svgjs="http://svgjs.dev/svgjs">
48
+ <g>
49
+ <path d="M11.6219,5.1455c-0.0003-0.0017-0.0012-0.0032-0.0015-0.0048c-0.0033-0.0173-0.0083-0.0343-0.0161-0.0502&#10;&#9;&#9;c-0.0086-0.0175-0.0199-0.034-0.0338-0.0487c-0.0053-0.0055-0.0119-0.0088-0.0176-0.0136&#10;&#9;&#9;c-0.0246-0.0207-0.0525-0.0365-0.0832-0.0431c-0.0378-0.0083-0.078-0.0056-0.1153,0.0093L8.399,6.1767&#10;&#9;&#9;C8.3763,6.1858,8.3568,6.1999,8.3393,6.216C8.3361,6.219,8.3329,6.2215,8.3299,6.2246c-0.0158,0.0166-0.0284,0.0357-0.0376,0.057&#10;&#9;&#9;c-0.0008,0.0018-0.0024,0.003-0.0032,0.0048l-0.5395,1.349L6.4982,1.1993c-0.002-0.0102-0.007-0.0192-0.0104-0.0288L6.3012,0.2141&#10;&#9;&#9;C6.2857,0.1355,6.2244,0.074,6.1459,0.0585C6.0681,0.0434,5.9871,0.0767,5.9433,0.1434l-4.9257,7.487&#10;&#9;&#9;c-0.011,0.0167-0.0187,0.0347-0.0241,0.0533c-0.0002,0.0007-0.0008,0.0012-0.001,0.002c-0.0007,0.0024,0,0.0049-0.0005,0.0072&#10;&#9;&#9;C0.9871,7.713,0.9859,7.7333,0.9875,7.7538c0.0005,0.0061,0.0009,0.0118,0.0019,0.0178c0.0039,0.0229,0.0104,0.0454,0.0224,0.0662&#10;&#9;&#9;L2.046,9.6167L0.3277,8.494C0.2674,8.4544,0.1902,8.4511,0.1269,8.4852c-0.0635,0.0341-0.1033,0.1001-0.104,0.172L0,11.2824&#10;&#9;&#9;c-0.0002,0.0267,0.0066,0.0516,0.0162,0.0753c0.0024,0.0058,0.0048,0.011,0.0077,0.0166c0.0118,0.0227,0.0266,0.0438,0.0464,0.0605&#10;&#9;&#9;c0.0003,0.0002,0.0003,0.0006,0.0007,0.0008l5.9106,4.9268c0.0031,0.0026,0.007,0.0035,0.0102,0.0058&#10;&#9;&#9;C6,16.3744,6.0082,16.3805,6.0173,16.3852c0.0028,0.0014,0.0053,0.003,0.0082,0.0043c0.0027,0.0012,0.0055,0.0016,0.0083,0.0028&#10;&#9;&#9;c0.0047,0.0019,0.0091,0.0037,0.0139,0.0053c0.0066,0.0022,0.0133,0.0039,0.0202,0.0053c0.003,0.0006,0.0055,0.0022,0.0085,0.0027&#10;&#9;&#9;c0.0104,0.0017,0.021,0.0025,0.0313,0.0025c0.0001,0,0.0001,0,0.0002,0c0.0001,0,0.0001-0.0001,0.0002-0.0001&#10;&#9;&#9;c0.0093,0,0.0186-0.0005,0.0279-0.0021c0.002-0.0003,0.0036-0.0017,0.0056-0.002c0.0068-0.0012,0.0137-0.0022,0.0203-0.0041&#10;&#9;&#9;c0.0051-0.0015,0.0098-0.0037,0.0148-0.0056c0.0024-0.0009,0.0049-0.0005,0.0072-0.0014c0.002-0.0008,0.0032-0.0025,0.0051-0.0034&#10;&#9;&#9;c0.0066-0.003,0.0131-0.0062,0.0193-0.01c0.0028-0.0016,0.0053-0.0032,0.0079-0.0049c0.002-0.0013,0.0042-0.0017,0.0061-0.0031&#10;&#9;&#9;c0.0022-0.0015,0.0032-0.0039,0.0053-0.0055c0.0049-0.0037,0.0099-0.0069,0.0144-0.0111c0.0025-0.0024,0.0042-0.0052,0.0066-0.0077&#10;&#9;&#9;c0.0081-0.0084,0.0164-0.0167,0.023-0.0267l0.0014-0.0022c0.0001,0,0.0001,0,0.0001-0.0001l1.1807-1.771l1.5889-2.3833&#10;&#9;&#9;l0.7754-1.1632c0.0443-0.0663,0.0441-0.153-0.0004-0.2191c-0.0446-0.0662-0.1239-0.0981-0.2028-0.0833l-0.5723,0.1161L11.6064,5.26&#10;&#9;&#9;c0.0038-0.0083,0.0048-0.0171,0.0074-0.0256c0.0032-0.0103,0.0076-0.0204,0.0089-0.031c0.0004-0.003-0.0003-0.006-0.0001-0.009&#10;&#9;&#9;C11.6241,5.178,11.6245,5.1616,11.6219,5.1455z M0.4138,9.021l0.2456,0.1605l0.2141,1.193l-0.4754,0.4488L0.4138,9.021z&#10;&#9;&#9; M0.4938,11.2751l0.5787-0.5465l3.2682,3.7531L0.4938,11.2751z M2.8047,10.1374L1.4545,7.8151l1.8657-1.0145l0.268,0.9764&#10;&#9;&#9;l1.9285,7.0254L2.8047,10.1374z M3.299,6.3636L1.7791,7.19l4.2278-6.4264l0.0874,0.4481L3.299,6.3636z M9.2254,11.1793&#10;&#9;&#9;L8.813,11.7979l-0.738-0.3853l0.6649-0.1348c0.0001,0,0.0001,0,0.0003,0L9.2254,11.1793z M7.7577,10.2479L7.8786,8.374&#10;&#9;&#9;l0.6604-1.651l0.5335,0.5794L7.7577,10.2479z M10.7687,6.1234l-0.3365,0.2091L9.3397,7.0111l-0.529-0.5746l2.2278-0.8912&#10;&#9;&#9;L10.7687,6.1234z"/>
50
+ <g>
51
+ <polygon points="14.6965,13.7003 21.6177,13.7003 21.6177,11.5939 17.3105,11.5939 17.3105,9.9388 21.2789,9.9388 21.2789,7.8323 &#10;&#9;&#9;&#9;17.3105,7.8323 17.3105,6.1773 21.636,6.1773 21.636,4.0719 14.6965,4.0719 &#9;&#9;"/>
52
+ <path d="M26.4696,11.8007c-0.1051,0.0194-0.1966,0.0291-0.2748,0.0291c-0.1131,0-0.2058-0.0172-0.2774-0.0495&#10;&#9;&#9;&#9;c-0.0722-0.0334-0.1255-0.083-0.16-0.1509c-0.0345-0.0668-0.0518-0.1509-0.0518-0.251V8.3593h1.2413V6.479h-1.2413V4.7486h-2.5951&#10;&#9;&#9;&#9;V6.479h-0.9218v1.8803h0.9218v3.2637c-0.0065,0.5042,0.0921,0.9244,0.2957,1.2596c0.2037,0.3351,0.508,0.5807,0.9121,0.7359&#10;&#9;&#9;&#9;c0.4046,0.1552,0.9046,0.2166,1.4999,0.1853c0.2947-0.0162,0.5495-0.0485,0.7644-0.0991&#10;&#9;&#9;&#9;c0.2144-0.0496,0.3798-0.0916,0.4957-0.1261l-0.3761-1.8242C26.6522,11.7663,26.5747,11.7824,26.4696,11.8007z"/>
53
+ <path d="M33.9108,6.7322c-0.3777-0.2316-0.8222-0.348-1.3329-0.348c-0.5328,0-0.9891,0.1293-1.3684,0.3879&#10;&#9;&#9;&#9;c-0.3793,0.2586-0.6503,0.6185-0.8135,1.0797h-0.0749V4.0719h-2.5014v9.6284h2.5951V9.6382&#10;&#9;&#9;&#9;c0.0032-0.2382,0.0479-0.4429,0.1342-0.6131c0.0862-0.1713,0.2085-0.3028,0.3669-0.3955c0.1578-0.0927,0.3421-0.139,0.5522-0.139&#10;&#9;&#9;&#9;c0.3325,0,0.5884,0.1024,0.7688,0.306c0.1805,0.2037,0.2688,0.4838,0.2656,0.8415v4.0621h2.5956V9.093&#10;&#9;&#9;&#9;c0.0027-0.5269-0.0996-0.9935-0.3082-1.4007C34.5815,7.2839,34.2884,6.965,33.9108,6.7322z"/>
54
+ <path d="M40.6348,9.3559L39.1678,9.093c-0.2758-0.0506-0.4617-0.1207-0.5571-0.2112c-0.0959-0.0916-0.1423-0.1896-0.139-0.2963&#10;&#9;&#9;&#9;c-0.0033-0.1509,0.0754-0.2672,0.2349-0.348c0.16-0.0819,0.3513-0.1228,0.5738-0.1228c0.1724,0,0.3297,0.0291,0.4725,0.0872&#10;&#9;&#9;&#9;c0.1427,0.0582,0.2602,0.1401,0.3507,0.2468c0.0905,0.1067,0.1422,0.2338,0.1551,0.3815h2.3877&#10;&#9;&#9;&#9;c-0.0312-0.765-0.348-1.3641-0.9514-1.7962c-0.6034-0.4332-1.4277-0.6498-2.4712-0.6498c-0.6864,0-1.2796,0.0927-1.7795,0.2759&#10;&#9;&#9;&#9;c-0.4999,0.1832-0.8841,0.4493-1.1518,0.7995c-0.2678,0.3491-0.4003,0.7747-0.3971,1.2757&#10;&#9;&#9;&#9;c-0.0032,0.5679,0.1783,1.0312,0.5452,1.3921c0.3669,0.3599,0.9186,0.6044,1.655,0.7338l1.279,0.2252&#10;&#9;&#9;&#9;c0.2818,0.0506,0.4898,0.1163,0.6234,0.1972c0.1325,0.0819,0.2004,0.1918,0.2047,0.3297c-0.0043,0.1497-0.083,0.2661-0.2382,0.348&#10;&#9;&#9;&#9;c-0.1551,0.0808-0.3518,0.1218-0.5899,0.1218c-0.2947,0-0.5387-0.0614-0.7311-0.1853c-0.1928-0.1239-0.3065-0.3006-0.341-0.529&#10;&#9;&#9;&#9;h-2.5768c0.0722,0.7391,0.4192,1.335,1.0414,1.7865c0.6222,0.4515,1.4853,0.6767,2.5887,0.6767&#10;&#9;&#9;&#9;c0.6681,0,1.2628-0.1024,1.7844-0.3071c0.5215-0.2058,0.9342-0.4967,1.2369-0.8749c0.3017-0.3782,0.4547-0.8232,0.4579-1.3372&#10;&#9;&#9;&#9;c-0.0032-0.5334-0.1853-0.959-0.5474-1.2769C41.9256,9.718,41.374,9.4906,40.6348,9.3559z"/>
55
+ <path d="M46.4252,8.5166c0.1692-0.1293,0.3664-0.1951,0.5926-0.1951c0.2888,0,0.5237,0.1002,0.7079,0.2985&#10;&#9;&#9;&#9;c0.1832,0.1993,0.292,0.4881,0.3265,0.8674h2.4071c-0.0032-0.626-0.1476-1.1723-0.4321-1.6378&#10;&#9;&#9;&#9;c-0.2855-0.4655-0.6874-0.8264-1.2068-1.0818c-0.5183-0.2554-1.1324-0.3836-1.8403-0.3836c-0.7833,0-1.4546,0.1562-2.0127,0.4687&#10;&#9;&#9;&#9;c-0.5571,0.3114-0.9859,0.7467-1.2833,1.307c-0.2974,0.5592-0.4461,1.2089-0.4461,1.9481c0,0.7402,0.1487,1.39,0.4461,1.9491&#10;&#9;&#9;&#9;c0.2974,0.5592,0.7262,0.9956,1.2833,1.307c0.5581,0.3114,1.2294,0.4676,2.0127,0.4676c0.7144,0,1.3296-0.1283,1.8457-0.3847&#10;&#9;&#9;&#9;c0.5151-0.2575,0.9137-0.6217,1.196-1.0937c0.2824-0.4719,0.4278-1.0257,0.4375-1.6615h-2.4071&#10;&#9;&#9;&#9;c-0.0194,0.25-0.0743,0.4622-0.167,0.6368c-0.0926,0.1735-0.2122,0.3049-0.3599,0.3943&#10;&#9;&#9;&#9;c-0.1476,0.0895-0.3168,0.1347-0.5075,0.1347c-0.2263,0-0.4234-0.0657-0.5926-0.195c-0.1691-0.1304-0.3006-0.3265-0.3943-0.5883&#10;&#9;&#9;&#9;c-0.0948-0.2618-0.1411-0.5894-0.1411-0.9848c0-0.3955,0.0463-0.723,0.1411-0.9849C46.1246,8.8431,46.2561,8.6469,46.4252,8.5166z&#10;&#9;&#9;&#9;"/>
56
+ <path d="M55.4319,6.3842c-0.3857,0-0.7219,0.1186-1.0085,0.3534c-0.2866,0.2349-0.4957,0.6067-0.6271,1.1142h-0.0755V6.479&#10;&#9;&#9;&#9;h-2.5202v7.2213h2.5957V9.9388c0-0.2759,0.0571-0.5161,0.1735-0.7208c0.1164-0.2058,0.2747-0.3653,0.4773-0.4806&#10;&#9;&#9;&#9;c0.2026-0.1142,0.4299-0.1714,0.6842-0.1714c0.1347,0,0.2963,0.0108,0.4838,0.0334c0.1886,0.0215,0.3469,0.055,0.4752,0.0981&#10;&#9;&#9;&#9;V6.4833c-0.1034-0.0313-0.2112-0.056-0.3222-0.0733C55.6571,6.3928,55.5451,6.3842,55.4319,6.3842z"/>
57
+ <path d="M57.908,5.7269c0.3501,0,0.6507-0.1164,0.8997-0.348c0.25-0.2322,0.3739-0.5112,0.3739-0.8372&#10;&#9;&#9;&#9;c0-0.3259-0.1239-0.605-0.3739-0.8367c-0.2489-0.2322-0.5506-0.348-0.9051-0.348c-0.3513,0-0.6519,0.1159-0.903,0.348&#10;&#9;&#9;&#9;c-0.25,0.2317-0.3761,0.5108-0.3761,0.8367c0,0.326,0.1261,0.605,0.3761,0.8372C57.2507,5.6105,57.5535,5.7269,57.908,5.7269z"/>
58
+ <rect x="56.6053" y="6.479" width="2.5957" height="7.2213"/>
59
+ <path d="M66.2111,6.7656c-0.431-0.2543-0.8846-0.3815-1.3609-0.3815c-0.3577,0-0.6713,0.0625-0.9407,0.1865&#10;&#9;&#9;&#9;c-0.2694,0.1239-0.4957,0.2877-0.6767,0.4934c-0.1821,0.2058-0.32,0.4299-0.4138,0.6745h-0.0571V6.479h-2.5762v9.929h2.5956&#10;&#9;&#9;&#9;v-3.8919h0.0377c0.1002,0.2446,0.2435,0.4622,0.4299,0.6551c0.1864,0.1929,0.4116,0.3448,0.6767,0.4569&#10;&#9;&#9;&#9;c0.2651,0.111,0.5667,0.1659,0.9051,0.1659c0.514,0,0.987-0.1346,1.418-0.4041c0.431-0.2693,0.7758-0.6788,1.0344-1.2272&#10;&#9;&#9;&#9;c0.2586-0.5485,0.3879-1.2392,0.3879-2.0731c0-0.8717-0.1358-1.5796-0.4073-2.1248C66.9934,7.4186,66.6421,7.0199,66.2111,6.7656z&#10;&#9;&#9;&#9; M64.8664,11.0088c-0.0895,0.2554-0.2177,0.4514-0.3857,0.5883c-0.1681,0.1358-0.3707,0.2036-0.6088,0.2036&#10;&#9;&#9;&#9;c-0.2382,0-0.4429-0.0689-0.6131-0.209c-0.1714-0.139-0.3028-0.3373-0.3955-0.5926c-0.0927-0.2554-0.139-0.5581-0.139-0.9094&#10;&#9;&#9;&#9;c0-0.3578,0.0463-0.6637,0.139-0.9191c0.0927-0.2554,0.2241-0.4515,0.3955-0.5883c0.1702-0.1358,0.375-0.2037,0.6131-0.2037&#10;&#9;&#9;&#9;c0.2381,0,0.4406,0.0678,0.6088,0.2037c0.1681,0.1368,0.2963,0.3329,0.3857,0.5883C64.9558,9.4259,65,9.7319,65,10.0897&#10;&#9;&#9;&#9;C65,10.4474,64.9558,10.7534,64.8664,11.0088z"/>
60
+ <path d="M72.2601,11.8007c-0.1046,0.0194-0.1972,0.0291-0.2748,0.0291c-0.1131,0-0.2058-0.0172-0.2779-0.0495&#10;&#9;&#9;&#9;c-0.0722-0.0334-0.125-0.083-0.1595-0.1509c-0.0345-0.0668-0.0518-0.1509-0.0518-0.251V8.3593h1.2413V6.479h-1.2413V4.7486&#10;&#9;&#9;&#9;h-2.5956V6.479h-0.9213v1.8803h0.9213v3.2637c-0.0065,0.5042,0.0926,0.9244,0.2963,1.2596&#10;&#9;&#9;&#9;c0.2037,0.3351,0.5075,0.5807,0.9126,0.7359c0.4041,0.1552,0.9041,0.2166,1.4999,0.1853&#10;&#9;&#9;&#9;c0.2941-0.0162,0.5495-0.0485,0.7639-0.0991c0.2144-0.0496,0.3803-0.0916,0.4957-0.1261l-0.3761-1.8242&#10;&#9;&#9;&#9;C72.4433,11.7663,72.3657,11.7824,72.2601,11.8007z"/>
61
+ <path d="M74.762,5.7269c0.3502,0,0.6508-0.1164,0.8997-0.348c0.25-0.2322,0.3738-0.5112,0.3738-0.8372&#10;&#9;&#9;&#9;c0-0.3259-0.1239-0.605-0.3738-0.8367c-0.2489-0.2322-0.5507-0.348-0.9051-0.348c-0.3512,0-0.6519,0.1159-0.903,0.348&#10;&#9;&#9;&#9;c-0.25,0.2317-0.376,0.5108-0.376,0.8367c0,0.326,0.126,0.605,0.376,0.8372C74.1048,5.6105,74.4076,5.7269,74.762,5.7269z"/>
62
+ <rect x="73.4594" y="6.479" width="2.5957" height="7.2213"/>
63
+ <path d="M82.5318,6.8529c-0.5581-0.3125-1.2294-0.4687-2.0127-0.4687c-0.7834,0-1.4546,0.1562-2.0127,0.4687&#10;&#9;&#9;&#9;c-0.5571,0.3114-0.9859,0.7467-1.2833,1.307c-0.2974,0.5592-0.4461,1.2089-0.4461,1.9481c0,0.7402,0.1487,1.39,0.4461,1.9491&#10;&#9;&#9;&#9;c0.2974,0.5592,0.7262,0.9956,1.2833,1.307c0.5581,0.3114,1.2294,0.4676,2.0127,0.4676c0.7833,0,1.4546-0.1562,2.0127-0.4676&#10;&#9;&#9;&#9;c0.5571-0.3114,0.9848-0.7478,1.2833-1.307c0.2974-0.5592,0.4461-1.2089,0.4461-1.9491c0-0.7392-0.1487-1.3889-0.4461-1.9481&#10;&#9;&#9;&#9;C83.5166,7.5996,83.0888,7.1643,82.5318,6.8529z M81.478,11.0627c-0.0873,0.2726-0.2112,0.4827-0.3717,0.6303&#10;&#9;&#9;&#9;c-0.1595,0.1476-0.3491,0.2209-0.5689,0.2209c-0.2317,0-0.431-0.0733-0.597-0.2209c-0.1659-0.1476-0.2931-0.3578-0.3803-0.6303&#10;&#9;&#9;&#9;c-0.0883-0.2726-0.1314-0.597-0.1314-0.973c0-0.3793,0.0431-0.7047,0.1314-0.9751c0.0873-0.2715,0.2144-0.4806,0.3803-0.6282&#10;&#9;&#9;&#9;c0.166-0.1476,0.3653-0.2209,0.597-0.2209c0.2198,0,0.4094,0.0733,0.5689,0.2209c0.1606,0.1476,0.2845,0.3567,0.3717,0.6282&#10;&#9;&#9;&#9;c0.0883,0.2705,0.1314,0.5958,0.1314,0.9751C81.6094,10.4657,81.5663,10.79,81.478,11.0627z"/>
64
+ <path d="M91.0752,6.7355c-0.3782-0.2338-0.8221-0.3513-1.3329-0.3513c-0.5301,0-0.9934,0.1304-1.39,0.3912&#10;&#9;&#9;&#9;c-0.3965,0.2596-0.6723,0.6184-0.8297,1.0764h-0.0754V6.479h-2.4632v7.2213h2.5957V9.6382&#10;&#9;&#9;&#9;c0.0022-0.2382,0.0463-0.4429,0.1314-0.6131c0.0841-0.1713,0.2058-0.3028,0.3642-0.3955c0.1584-0.0927,0.3438-0.139,0.5571-0.139&#10;&#9;&#9;&#9;c0.3265,0,0.5807,0.1024,0.7639,0.306c0.1832,0.2037,0.2737,0.4838,0.2705,0.8415v4.0621h2.5957V9.093&#10;&#9;&#9;&#9;c0.0032-0.5237-0.1002-0.9891-0.3082-1.3965C91.7454,7.2893,91.4534,6.9682,91.0752,6.7355z"/>
65
+ </g>
66
+ <path d="M99.4526,10.0358c-0.362-0.3178-0.9137-0.5452-1.6529-0.6798L96.3322,9.093c-0.2758-0.0506-0.4612-0.1207-0.5571-0.2112&#10;&#9;&#9;c-0.0959-0.0916-0.1411-0.1896-0.1379-0.2963c-0.0032-0.1509,0.0743-0.2672,0.2349-0.348&#10;&#9;&#9;c0.1595-0.0819,0.3502-0.1228,0.5732-0.1228c0.1723,0,0.3297,0.0291,0.473,0.0872c0.1422,0.0582,0.2586,0.1401,0.3501,0.2468&#10;&#9;&#9;c0.0905,0.1067,0.1423,0.2338,0.1552,0.3815h2.3877c-0.0313-0.765-0.348-1.3641-0.9514-1.7962&#10;&#9;&#9;c-0.6034-0.4332-1.4277-0.6498-2.4707-0.6498c-0.6863,0-1.28,0.0927-1.78,0.2759s-0.8836,0.4493-1.1519,0.7995&#10;&#9;&#9;c-0.2683,0.3491-0.4008,0.7747-0.3976,1.2757c-0.0032,0.5679,0.1788,1.0312,0.5452,1.3921&#10;&#9;&#9;c0.3674,0.3599,0.9191,0.6044,1.655,0.7338l1.279,0.2252c0.2823,0.0506,0.4902,0.1163,0.6239,0.1972&#10;&#9;&#9;c0.1325,0.0819,0.2004,0.1918,0.2036,0.3297c-0.0032,0.1497-0.0819,0.2661-0.237,0.348c-0.1551,0.0808-0.3524,0.1218-0.5905,0.1218&#10;&#9;&#9;c-0.2942,0-0.5377-0.0614-0.7305-0.1853c-0.1929-0.1239-0.3071-0.3006-0.3416-0.529h-2.5762&#10;&#9;&#9;c0.0722,0.7391,0.4192,1.335,1.0419,1.7865c0.6217,0.4515,1.4848,0.6767,2.5881,0.6767c0.668,0,1.2628-0.1024,1.7843-0.3071&#10;&#9;&#9;c0.5215-0.2058,0.9342-0.4967,1.237-0.8749c0.3017-0.3782,0.4547-0.8232,0.4579-1.3372&#10;&#9;&#9;C99.9968,10.7793,99.8147,10.3537,99.4526,10.0358z"/>
67
+ </g>
68
+ </svg>
69
+ """
70
+
71
+ python_token_code = r"""
72
+ # ethpen.com
73
+ # 最后更新日期:2023 年 8 月 18 日
74
+
75
+ # 在使用之前,敬请仔细阅读说明,感谢您的配合。
76
+ # 请务必访问 ethpen.com 官方网站。您可以确保这里的代码无恶意,安全地复制。
77
+ # 你只需要掌握一些 python 相关的基础。
78
+ # 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
79
+ # 我们建议您使用备用账号,并避免在账号中存放大额资金。
80
+ # 若您对此代码存有疑虑,建议您利用如 ChetGPT、Bard 或 Claude 等知名 AI 平台进行查询,以判断是否含有恶意代码。
81
+ # 如果你在使用的过程中发现 BUG 或者有什么想法和建议,欢迎与我联系。
82
+
83
+ # 导入运行代码所需要的库
84
+ from web3 import Web3 # 与以太坊交互的库,安装的命令是 pip install web3
85
+ import hashlib # 用于数据哈希,安装的命令是 pip install hashlib
86
+ import requests # 用于发送网络请求,安装的命令是 pip install requests
87
+ import re # 用于正则表达式
88
+ import time # 用于时间相关
89
+
90
+ # ---------- 以下是基础配置 ----------
91
+
92
+ # 填写你的多个 ETH 地址及私钥,建议填写新建的钱包,用英文逗号分隔(,),如下:地址,私钥。
93
+ accounts_str = '''
94
+ 0xa62C8d0bB4F4530b9B68a14DaF8A949Cb01dB986,4de9b2812d51ba0ebbe7c990947b12544f7926a7aa1ebac084d42f6c7c8afbc1
95
+ 0x71D10cc20Abe0af4EC16170C502a4319DE0e40B4,377f4a19719337b63d8280f0a52769a42b534343de1eccab4f6d204d1ca04815
96
+ 0xBe169Ae4AD317B5632DE6Ae0e1EfeF0b22B1f91e,24fdf2ed0b820307582b06e1ed0b2047b4371e9d682e0b32455d310e08baafc5
97
+ '''
98
+
99
+ # 需要题写的代币铭文内容,变动的部分文本如 id 请用 "@#" 代替,例如:'data:,{"p":"erc-20","op":"mint","tick":"eths","id":"@#","amt":"1000"}'
100
+ ethscription = 'data:,{"p":"erc-20","op":"mint","tick":"eths","id":"@#","amt":"1000"}'
101
+
102
+ # 设置代币铭文 id 的起始和结束范围
103
+ min_id = 100 # 开始的整数
104
+ max_id = 888 # 结束的整数
105
+
106
+ # 决定是否在题写铭文之前检查该铭文有没有被题写过,如果需要检查就填写 Ture 如果不需要就填 False
107
+ check = False
108
+
109
+ # 每次交易成功后暂停 N 秒,0 为不暂停
110
+ sleep_sec = 0
111
+
112
+ # 这里配置 Ethereum PRC URL,如果你没有,请到 infura.io 或者 alchemy.com 申请一个免费的 API
113
+ w3 = Web3(Web3.HTTPProvider('https://sepolia.infura.io/v3/eab7f935b9af45e1a54f7d7ed06c5206'))
114
+
115
+ # 连接的网络 ID。比如说,1 代表 Mainnet,5 代表 Goerli 测试网络,11155111 代表 Sepolia 测试网络,如果你不放心,可以先用测试网试试。
116
+ chain_id = 11155111
117
+
118
+ # ---------- 以上是基础配置 ----------
119
+
120
+
121
+ # 检查 ETH 地址是否有效
122
+ def is_valid_eth_address(address):
123
+ if re.match("^0x[0-9a-fA-F]{40}$", address):
124
+ return True
125
+ return False
126
+
127
+
128
+ # 检查 Ethereum 私钥是否有效
129
+ def is_valid_eth_private_key(private_key):
130
+ if re.match("^[0-9a-fA-F]{64}$", private_key):
131
+ return True
132
+ return False
133
+
134
+
135
+ # 验证输入的铭文文本是否含有空格和换行符,而且字母全部为小写
136
+ def validate_input(data_str):
137
+ if re.search(r'[A-Z\s\n]', data_str): # 查找大写字母、空格或换行符
138
+ return False
139
+ return True
140
+
141
+
142
+ # 把文字转换成 16 进制
143
+ def text_to_hex(text):
144
+ return ''.join(format(ord(char), '02x') for char in text)
145
+
146
+
147
+ # 使用sha256算法计算哈希
148
+ def sha256(input_string):
149
+ sha256 = hashlib.sha256()
150
+ sha256.update(input_string.encode('utf-8'))
151
+ return sha256.hexdigest()
152
+
153
+
154
+ # 使用 Ethscriptions API(主网)检查某个铭文是否已题写
155
+ def check_content_exists(sha):
156
+ # 定义请求的网址
157
+ endpoint = f"/ethscriptions/exists/{sha}"
158
+ response = requests.get('https://mainnet-api.ethscriptions.com/api' + endpoint)
159
+ # 如果返回状态码是200,说明请求成功,然后返回结果(Ture or False)
160
+ if response.status_code == 200:
161
+ return response.json()['result']
162
+
163
+
164
+ # 发送自己到自己 0ETH 的交易
165
+ def send_transaction(w3, account_address, private_key, chain_id, gas_price, input_data, current_nonce):
166
+
167
+ # 设置交易的相关信息
168
+ tx = {
169
+ 'chainId': chain_id, # 网络 ID
170
+ 'gas': 25000, # 如果交易 gas 过低,可适当调高
171
+ 'gasPrice': gas_price, # gas 的价格
172
+ 'nonce': current_nonce, # 账户的交易数
173
+ 'to': account_address, # 接收地址为自己
174
+ 'value': 0, # 金额为 0ETH
175
+ 'data': text_to_hex(input_data), # 铭文内容
176
+ }
177
+
178
+ # 用私钥签名这个交易
179
+ signed_tx = w3.eth.account.sign_transaction(tx, private_key)
180
+ # 发送签名后的交易并获取交易哈希
181
+ tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
182
+ # 打印结果信息
183
+ print(f'{account_address} | {input_data} | Transaction Hash: {tx_hash.hex()}')
184
+
185
+
186
+ # 初始化当前账户索引为 0
187
+ current_account_index = 0
188
+ # 创建账户列表
189
+ accounts = []
190
+ # 使用字典来跟踪每个地址��nonce
191
+ nonces = {}
192
+
193
+
194
+ if accounts_str: # 如果账户列表有内容
195
+ for line in accounts_str.strip().split('\n'): # 先去掉首尾的空白,然后根据换行符划分账户
196
+ if ',' in line: # 检查是否包含逗号
197
+ address, key = line.split(',') # 分开地址和私钥
198
+ if is_valid_eth_address(address) and is_valid_eth_private_key(key): # 验证地址和私钥
199
+ current_nonce = w3.eth.get_transaction_count(address) # 获取地址的 nonce
200
+ nonces[address] = current_nonce # 记录地址的 nonce
201
+ accounts.append((address.strip(), key.strip())) # 保存地址和私钥还有 nonce
202
+ else:
203
+ print(f"地址 {address} 或私钥 {key} 无效,请检查!")
204
+ exit()
205
+ else:
206
+ print(f"输入格式错误,请确保每行包含一个地址和一个私钥,并使用英文逗号分隔(,)。错误行:**{line}**")
207
+ exit()
208
+
209
+ # 判断铭文文本里是否包含空格、换行符,而且所有的字母都必须为小写。
210
+ if not validate_input(ethscription):
211
+ print("请注意:通常代币铭文文本里不能包含空格、换行符,而且所有的字母都必须为小写。")
212
+
213
+ # 检查是否留空
214
+ if not accounts or not ethscription:
215
+ print('请正确谨慎地填写内容,每一项都不应留空。')
216
+ exit()
217
+ else:
218
+ print('看起来你输入的内容均无没有问题!')
219
+
220
+ # 认真检查铭文内容,如果发现错误,输入 1 结束
221
+ print(f'铭文文本:\033[44m{ethscription}\033[m,题写 id 范围为:{min_id} - {max_id}。')
222
+ if input('请预览铭文,输入任意内容继续,输入 1 退出程序:') == '1':
223
+ exit()
224
+ print(f'开始任务,需要题写的铭文总量为:{max_id - min_id + 1}')
225
+
226
+ # 对代币铭文 id 进行循环
227
+ for the_id in range(min_id, max_id + 1):
228
+ # 使用当前账户发送交易
229
+ address, key = accounts[current_account_index]
230
+ # 得到完整的铭文文本
231
+ input_data = ethscription.replace('@#', str(the_id))
232
+ # 获取 gas
233
+ gas_price = w3.eth.gas_price
234
+ # 根据是否检查的开关进行
235
+ if check:
236
+ # 这里是开了检查后请求 Ethscriptions API
237
+ if check_content_exists(sha256(input_data)):
238
+ # 返回数据为 Ture,说明该铭文已经被题写,打印信息
239
+ print(f'{input_data} 已经被题写!')
240
+ else:
241
+ # 返回数据为 False,说明该铭文还没被题写,发送交易
242
+ # 使用 current_nonce 发送交易
243
+ send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
244
+ # 交易成功后,手动增加 nonce 值
245
+ nonces[address] += 1
246
+ else:
247
+ # 这里是未开检查后直接发送交易
248
+ # 使用 current_nonce 发送交易
249
+ send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
250
+ # 交易成功后,手动增加 nonce 值
251
+ nonces[address] += 1
252
+ # 更新当前账户索引,确保索引始终在账户列表的范围内
253
+ current_account_index = (current_account_index + 1) % len(accounts)
254
+ # 暂停 sleep_sec 秒
255
+ time.sleep(sleep_sec)
256
+
257
+ print(f'所有任务已经完成。')
258
+
259
+ """
260
+
261
+ python_name_code = r"""
262
+ # ethpen.com
263
+ # 最后更新日期:2023 年 8 月 18 日
264
+
265
+ # 在使用之前,敬请仔细阅读说明,感谢您的配合。
266
+ # 请务必访问 ethpen.com 官方网站。您可以确保这里的代码无恶意,安全地复制。
267
+ # 你只需要掌握一些 python 相关的基础。
268
+ # 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
269
+ # 我们建议您使用备用账号,并避免在账号中存放大额资金。
270
+ # 若您对此代码存有疑虑,建议您利用如 ChetGPT、Bard 或 Claude 等知名 AI 平台进行查询,以判断是否含有恶意代码。
271
+ # 如果你在使用的过程中发现 BUG 或者有什么想法和建议,欢迎与我联系。
272
+
273
+ # 导入运行代码所需要的库
274
+ from web3 import Web3 # 与以太坊交互的库,安装的命令是 pip install web3
275
+ import hashlib # 用于数据哈希,安装的命令是 pip install hashlib
276
+ import requests # 用于发送网络请求,安装的命令是 pip install requests
277
+ import re # 用于正则表达式
278
+ import time # 用于时间相关
279
+
280
+ # ---------- 以下是基础配置 ----------
281
+
282
+ # 填写你的多个 ETH 地址及私钥,建议填写新建的钱包,用英文逗号分隔(,),如下:地址,私钥。
283
+ accounts_str = '''
284
+ 0xa62C8d0bB4F4530b9B68a14DaF8A949Cb01dB986,4de9b2812d51ba0ebbe7c990947b12544f7926a7aa1ebac084d42f6c7c8afbc1
285
+ 0x71D10cc20Abe0af4EC16170C502a4319DE0e40B4,377f4a19719337b63d8280f0a52769a42b534343de1eccab4f6d204d1ca04815
286
+ 0xBe169Ae4AD317B5632DE6Ae0e1EfeF0b22B1f91e,24fdf2ed0b820307582b06e1ed0b2047b4371e9d682e0b32455d310e08baafc5
287
+ '''
288
+
289
+ # 需要题写的铭文内容,在三个单引号内输入多个域名铭文,可以用空格、换行符、英文逗号(,)分开��不要带 data:, 开头
290
+ # 不要带 data:, 开头
291
+ # 不要带 data:, 开头
292
+ ethscription = '''
293
+ 123
294
+ 12313131
295
+ 2131 21313
296
+ 12313 32313
297
+ 423213v ethpen.com
298
+ '''
299
+ # 你希望添加的后缀
300
+ suffix = '.eths'
301
+ # 以空格、换行符、英文逗号分隔文本,并加上后缀
302
+ ethscription_list = [item.strip() + suffix for item in re.split(r'[\s,]+', ethscription) if item]
303
+
304
+ # 决定是否在题写铭文之前检查该铭文有没有被题写过,如果需要检查就填写 Ture 如果不需要就填 False
305
+ check = False
306
+
307
+ # 每次交易成功后暂停 N 秒,0 为不暂停
308
+ sleep_sec = 0
309
+
310
+ # 这里配置 Ethereum PRC URL,如果你没有,请到 infura.io 或者 alchemy.com 申请一个免费的 API
311
+ w3 = Web3(Web3.HTTPProvider('https://sepolia.infura.io/v3/eab7f935b9af45e1a54f7d7ed06c5206'))
312
+
313
+ # 连接的网络 ID。比如说,1 代表 Mainnet,5 代表 Goerli 测试网络,11155111 代表 Sepolia 测试网络,如果你不放心,可以先用测试网试试。
314
+ chain_id = 11155111
315
+
316
+ # ---------- 以上是基础配置 ----------
317
+
318
+
319
+ # 检查 ETH 地址是否有效
320
+ def is_valid_eth_address(address):
321
+ if re.match("^0x[0-9a-fA-F]{40}$", address):
322
+ return True
323
+ return False
324
+
325
+
326
+ # 检查 Ethereum 私钥是否有效
327
+ def is_valid_eth_private_key(private_key):
328
+ if re.match("^[0-9a-fA-F]{64}$", private_key):
329
+ return True
330
+ return False
331
+
332
+
333
+ # 验证输入的铭文文本是否含有空格和换行符,而且字母全部为小写
334
+ def validate_input(data_str):
335
+ if re.search(r'[A-Z\s\n]', data_str): # 查找大写字母、空格或换行符
336
+ return False
337
+ return True
338
+
339
+
340
+ # 把文字转换成 16 进制
341
+ def text_to_hex(text):
342
+ return ''.join(format(ord(char), '02x') for char in text)
343
+
344
+
345
+ # 使用sha256算法计算哈希
346
+ def sha256(input_string):
347
+ sha256 = hashlib.sha256()
348
+ sha256.update(input_string.encode('utf-8'))
349
+ return sha256.hexdigest()
350
+
351
+
352
+ # 使用 Ethscriptions API(主网)检查某个铭文是否已存在
353
+ def check_content_exists(sha):
354
+ # 定义请求的网址
355
+ endpoint = f"/ethscriptions/exists/{sha}"
356
+ response = requests.get('https://mainnet-api.ethscriptions.com/api' + endpoint)
357
+ # 如果返回状态码是200,说明请求成功,然后返回结果(Ture or False)
358
+ if response.status_code == 200:
359
+ return response.json()['result']
360
+
361
+
362
+ # 发送自己到自己 0ETH 的交易
363
+ def send_transaction(w3, account_address, private_key, chain_id, gas_price, input_data, current_nonce):
364
+
365
+ # 设置交易的相关信息
366
+ tx = {
367
+ 'chainId': chain_id, # 网络 ID
368
+ 'gas': 25000, # 如果交易 gas 过低,可适当调高
369
+ 'gasPrice': gas_price, # gas 的价格
370
+ 'nonce': current_nonce, # 账户的交易数
371
+ 'to': account_address, # 接收地址为自己
372
+ 'value': 0, # 金额为 0ETH
373
+ 'data': text_to_hex(input_data), # 铭文内容
374
+ }
375
+
376
+ # 用私钥签名这个交易
377
+ signed_tx = w3.eth.account.sign_transaction(tx, private_key)
378
+ # 发送签名后的交易并获取交易哈希
379
+ tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
380
+ # 打印结果信息
381
+ print(f'{account_address} | {input_data} | Transaction Hash: {tx_hash.hex()}')
382
+
383
+
384
+ # 初始化当前账户索引为 0
385
+ current_account_index = 0
386
+ # 创建账户列表
387
+ accounts = []
388
+ # 使用字典来跟踪每个地址的nonce
389
+ nonces = {}
390
+
391
+
392
+ if accounts_str: # 如果账户列表有内容
393
+ for line in accounts_str.strip().split('\n'): # 先去掉首尾的空白,然后根据换行符划分账户
394
+ if ',' in line: # 检查是否包含逗号
395
+ address, key = line.split(',') # 分开地址和私钥
396
+ if is_valid_eth_address(address) and is_valid_eth_private_key(key): # 验证地址和私钥
397
+ current_nonce = w3.eth.get_transaction_count(address) # 获取地址的 nonce
398
+ nonces[address] = current_nonce # 记录地址的 nonce
399
+ accounts.append((address.strip(), key.strip())) # 保存地址和私钥还有 nonce
400
+ else:
401
+ print(f"地址 {address} 或私钥 {key} 无效,请检查!")
402
+ exit()
403
+ else:
404
+ print(f"输入格式错误,请确保每行包含一个地址和一个私钥,并使用英文逗号分隔(,)。错误行:**{line}**")
405
+ exit()
406
+
407
+ # 判断铭文文本里是否包含空格、换行符,而且所有的字母都必须为小写。
408
+ if not validate_input(ethscription):
409
+ print("请注意:通常代币铭文文本里不能包含空格、换行符,而且所有的字母都必须为小写。")
410
+
411
+ # 检查是否留空
412
+ if not accounts or not ethscription:
413
+ print('请正确谨慎地填写内容,每一项都不应留空。')
414
+ exit()
415
+ else:
416
+ print('看起来你输入的内容均无没有问题!')
417
+
418
+ # 认真检查铭文内容,如果发现错误,输入 1 结束
419
+ for i in ethscription_list:
420
+ print(f'\033[44m{i}\033[m')
421
+ if input('请预览铭文,输入任意内容继续��输入 1 退出程序:') == '1':
422
+ exit()
423
+ print(f'开始任务,需要题写的铭文总量为:{len(ethscription_list)}')
424
+
425
+ # 对代币铭文 id 进行循环
426
+ for name_str in ethscription_list:
427
+ # 使用当前账户发送交易
428
+ address, key = accounts[current_account_index]
429
+ # 得到完整的铭文文本
430
+ if not name_str.startswith('data:,'):
431
+ input_data = f'data:,{name_str}'
432
+ else:
433
+ input_data = name_str
434
+ # 获取 gas
435
+ gas_price = w3.eth.gas_price
436
+ # 根据是否检查的开关进行
437
+ if check:
438
+ # 这里是开了检查后请求 Ethscriptions API
439
+ if check_content_exists(sha256(input_data)):
440
+ # 返回数据为 Ture,说明该铭文已经被题写,打印信息
441
+ print(f'{input_data} 已经被题写!')
442
+ else:
443
+ # 返回数据为 False,说明该铭文还没被题写,发送交易
444
+ # 使用 current_nonce 发送交易
445
+ send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
446
+ # 交易成功后,手动增加 nonce 值
447
+ nonces[address] += 1
448
+ else:
449
+ # 这里是未开检查后直接发送交易
450
+ # 使用 current_nonce 发送交易
451
+ send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
452
+ # 交易成功后,手动增加 nonce 值
453
+ nonces[address] += 1
454
+ # 更新当前账户索引,确保索引始终在账户列表的范围内
455
+ current_account_index = (current_account_index + 1) % len(accounts)
456
+ # 暂停 sleep_sec 秒
457
+ time.sleep(sleep_sec)
458
+
459
+ print(f'所有任务已经完成。')
460
+
461
+ """
462
+
463
+ hf_token_code = r"""
464
+ # ethpen.com
465
+ # 最后更新日期:2023 年 8 月 18 日
466
+
467
+ # 在使用之前,敬请仔细阅读说明,感谢您的配合。
468
+ # 请务必访问 ethpen.com 官方网站。您可以确保这里的代码无恶意,安全地复制。
469
+ # 你只需要拥有一个 HuggingFace.co 账户。
470
+ # 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
471
+ # 我们建议您使用备用账号,并避免在账号中存放大额资金。
472
+ # 若您对此代码存有疑虑,建议您利用如 ChetGPT、Bard 或 Claude 等知名 AI 平台进行查询,以判断是否含有恶意代码。
473
+ # 请查看我们的例子 https://ethscriptions-name.hf.space。
474
+
475
+ # 导入运行代码所需要的库
476
+ import streamlit as st # streamlit app
477
+ from web3 import Web3 # 与以太坊交互的库
478
+ import hashlib # 用于数据哈希
479
+ import requests # 用于发送网络请求
480
+ import re # 用于正则表达式
481
+ import time # 用于时间相关
482
+
483
+
484
+ # 检查 ETH 地址是否有效
485
+ def is_valid_eth_address(address):
486
+ if re.match("^0x[0-9a-fA-F]{40}$", address):
487
+ return True
488
+ return False
489
+
490
+
491
+ # 检查 Ethereum 私钥是否有效
492
+ def is_valid_eth_private_key(private_key):
493
+ if re.match("^[0-9a-fA-F]{64}$", private_key):
494
+ return True
495
+ return False
496
+
497
+
498
+ # 验证输入的铭文文本是否含有空格和换行符,而且字母全部为小写
499
+ def validate_input(data_str):
500
+ if re.search(r'[A-Z\s\n]', data_str): # 查找大写字母、空格或换行符
501
+ return False
502
+ return True
503
+
504
+
505
+ # 把文字转换成 16 进制
506
+ def text_to_hex(text):
507
+ return ''.join(format(ord(char), '02x') for char in text)
508
+
509
+
510
+ # 使用sha256算法计算哈希
511
+ def sha256(input_string):
512
+ sha256 = hashlib.sha256()
513
+ sha256.update(input_string.encode('utf-8'))
514
+ return sha256.hexdigest()
515
+
516
+
517
+ # 使用 Ethscriptions API(主网)检查某个铭文是否已题写
518
+ def check_content_exists(sha):
519
+ # 定义请求的网址
520
+ endpoint = f"/ethscriptions/exists/{sha}"
521
+ response = requests.get('https://mainnet-api.ethscriptions.com/api' + endpoint)
522
+ # 如果返回状态码是200,说明请求成功,然后返回结果(Ture or False)
523
+ if response.status_code == 200:
524
+ return response.json()['result']
525
+
526
+
527
+ # 发送自己到自己 0ETH 的交易
528
+ def send_transaction(w3, account_address, private_key, chain_id, gas_price, input_data, current_nonce):
529
+
530
+ # 设置交易的相关信息
531
+ tx = {
532
+ 'chainId': chain_id, # 网络 ID
533
+ 'gas': 25000, # 如果交易 gas 过低,可适当调高
534
+ 'gasPrice': gas_price, # gas 的价格
535
+ 'nonce': current_nonce,
536
+ 'to': account_address, # 接收地址为自己
537
+ 'value': 0, # 金额为 0ETH
538
+ 'data': text_to_hex(input_data), # 铭文内容
539
+ }
540
+
541
+ # 用私钥签名这个交易
542
+ signed_tx = w3.eth.account.sign_transaction(tx, private_key)
543
+ # 发送签名后的交易并获取交易哈希
544
+ tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
545
+ # 打印结果信息
546
+ st.toast(f'{input_data}', icon='✅')
547
+ # 返回铭文还有交易哈希
548
+ return input_data, tx_hash.hex()
549
+
550
+ # 网页前端显示
551
+ # 网页标题
552
+ st.markdown('# [ethpen.com](https://ethpen.com) 代币铭文批量题写')
553
+ # 提醒
554
+ st.info('''在使用之前,敬请仔细阅读���明,感谢您的配合。
555
+ - 请务必访问 **[ethpen.com](https://ethpen.com)** 官方网站。您可以确保这里的代码无恶意,安全地复制。
556
+ - 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
557
+ - 我们建议您使用备用账号,并避免在账号中存放大额资金。
558
+ - 若您对此代码存有疑虑,建议您利用如 [ChetGPT](https://chat.openai.com/)、[Bard](https://bard.google.com/) 或 [Claude](https://claude.ai/) 等知名 AI 平台进行查询,以判断是否含有恶意代码。
559
+ ''')
560
+
561
+ # 连接的网络 ID。比如说,1 代表 Mainnet,5 代表 Goerli 测试网络,11155111 代表 Sepolia 测试网络,如果你不放心,可以先用测试网试试。
562
+ net_options = {
563
+ '1': 'Mainnet',
564
+ '5': 'Goerli',
565
+ '11155111': 'Sepolia'
566
+ }
567
+ selected_option = st.selectbox(
568
+ '**网络 ID**',
569
+ list(net_options.keys()),
570
+ format_func=lambda x: f"{x} ({net_options[x]})"
571
+ )
572
+ chain_id = int(selected_option)
573
+
574
+ # 这里配置 Ethereum PRC URL,如果你没有,请到 infura.io 或者 alchemy.com 申请一个免费的 API
575
+ token_eth_prc_url = st.text_input(
576
+ f'**Ethereum PRC 链接**:选填,你可以去 [infura.io](https://app.infura.io/) 或者 [alchemy.com](https://alchemy.com/) 免费申请一个',
577
+ f'https://{net_options[str(chain_id)]}.infura.io/v3/eab7f935b9af45e1a54f7d7ed06c5206')
578
+ w3 = Web3(Web3.HTTPProvider(f'{token_eth_prc_url}'))
579
+
580
+ # 初始化当前账户索引为 0
581
+ current_account_index = 0
582
+ # 收集和显示所有交易的结果
583
+ transaction_results = []
584
+ # 创建账户列表
585
+ accounts = []
586
+ # 使用字典来跟踪每个地址的nonce
587
+ nonces = {}
588
+
589
+ # 启用多账户操作
590
+ if st.checkbox(f'启用**多账户**操作'):
591
+ # 多账户的文本框
592
+ account_list = st.text_area(f'输入多个 **ETH 地址及其对应的私钥**,用英文逗号分隔(,),如下:地址,私钥')
593
+ if account_list: # 如果账户列表有内容
594
+ for line in account_list.split('\n'): # 根据换行符划分账户
595
+ if ',' in line: # 检查是否包含逗号
596
+ address, key = line.split(',') # 分开地址和私钥
597
+ if is_valid_eth_address(address) and is_valid_eth_private_key(key): # 验证地址和私钥
598
+ current_nonce = w3.eth.get_transaction_count(address) # 获取地址的 nonce
599
+ nonces[address] = current_nonce # 记录地址的 nonce
600
+ accounts.append((address.strip(), key.strip())) # 保存地址和私钥还有 nonce
601
+ else:
602
+ st.error(f"地址 {address} 或私钥 {key} 无效,请检查!")
603
+ st.stop()
604
+ else:
605
+ st.error(f"输入格式错误,请确保每行包含一个地址和一个私钥,并使用英文逗号分隔(,)。错误行:**{line}**")
606
+ st.stop()
607
+ else:
608
+ account_address = st.text_input('填写你的 **ETH 地址**:')
609
+ private_key = st.text_input('填写你的 **ETH 地址对应的私钥**:', type="password")
610
+ if account_address and private_key: # 如果地址和私钥有内容
611
+ if is_valid_eth_address(account_address) and is_valid_eth_private_key(private_key): # 验证地址和私钥
612
+ current_nonce = w3.eth.get_transaction_count(account_address) # 获取地址的 nonce
613
+ nonces[account_address] = current_nonce # 记录地址的 nonce
614
+ accounts.append((account_address.strip(), private_key.strip())) # 保存地址和私钥还有 nonce
615
+ else:
616
+ st.error("地址或私钥无效,请检查!")
617
+ st.stop()
618
+
619
+ # 配置铭文文本
620
+ token_protocol = st.text_input('填写需要题写代币铭文协议 **Protocol(p)**:', 'erc-20')
621
+ token_operation = st.text_input('填写需要题写代币铭文操作 **Operation(op)**:', 'mint')
622
+ token_ticker = st.text_input('填写需要题写代币铭文简称 **Ticker(tick)**:')
623
+ token_min_id = st.number_input('填写需要题写代币铭文范围的**最小 ID(id)**:', min_value=1, value=1, step=1)
624
+ token_max_id = st.number_input('填写需要题写代币铭文范围的**最大 ID(id)**:', value=21000, step=1)
625
+ token_amount = st.number_input('填写需要题写代币铭文数量 **Amount(amt)**:', min_value=1, value=1000, step=1)
626
+ st.markdown('###### 预览你需要题写的代币铭文:')
627
+ st.code(
628
+ f'data:,{{"p":"{token_protocol}","op":"{token_operation}","tick":"{token_ticker}","id":"{token_min_id}","amt":"{token_amount}"}}',
629
+ language="json", line_numbers=False)
630
+ # 判断铭文文本里是否包含空格、换行符,而且所有的字母都必须为小写。
631
+ if not validate_input(
632
+ f'data:,{{"p":"{token_protocol}","op":"{token_operation}","tick":"{token_ticker}","id":"{token_min_id}","amt":"{token_amount}"}}'):
633
+ st.warning("**请注意**:通常代币铭文文本里不能包含空格、换行符,而且所有的字母都必须为小写。")
634
+
635
+ # 题写铭文之前检查该铭文有没有被题写
636
+ if st.checkbox(f'题写铭��之前**检查该铭文有没有被题写**'):
637
+ token_check = True
638
+ else:
639
+ token_check = False
640
+
641
+ # 每次交易成功后暂停 3 秒
642
+ if st.checkbox(f'每次交易完成后暂停 3 秒'):
643
+ sleep_3s = True
644
+ else:
645
+ sleep_3s = False
646
+
647
+ # 点击发送交易开始
648
+ if st.button(f'开始**发送交易**'):
649
+ if not accounts or not token_protocol or not token_operation or not token_ticker: # 检查是否留空
650
+ st.error(f'请正确谨慎地填写内容,每一项都**不应留空**。')
651
+ st.stop()
652
+ else:
653
+ st.toast('看起来你输入的内容均无没有问题!', icon='🥳')
654
+
655
+ st.toast(f'开始任务,需要题写的铭文总量为:{token_max_id - token_min_id + 1}', icon='😎')
656
+
657
+ # 对代币铭文 id 进行循环
658
+ for the_id in range(token_min_id, token_max_id + 1):
659
+ # 使用当前账户发送交易,获取当前账户的 nonce
660
+ address, key = accounts[current_account_index]
661
+ # 得到完整的铭文文本
662
+ input_data = f'data:,{{"p":"{token_protocol}","op":"{token_operation}","tick":"{token_ticker}","id":"{the_id}","amt":"{token_amount}"}}'
663
+ # 获取 gas
664
+ gas_price = w3.eth.gas_price
665
+ # 根据是否检查的开关进行
666
+ if token_check:
667
+ # 这里是开了检查后请求 Ethscriptions API
668
+ if check_content_exists(sha256(input_data)):
669
+ # 返回数据为 Ture,说明该铭文已经被题写,打印信息
670
+ st.toast(f'{input_data} 已经被题写!', icon='☹️')
671
+ else:
672
+ # 返回数据为 False,说明该铭文还没被题写,发送交易
673
+ # 使用 current_nonce 发送交易
674
+ data, tx_hash = send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
675
+ # 记录最后输出的结果
676
+ transaction_results.append(f"{address} | {data} | Transaction Hash: {tx_hash}")
677
+ # 交易成功后,手动增加 nonce 值
678
+ nonces[address] += 1
679
+ else:
680
+ # 这里是未开检查后直接发送交易
681
+ # 使用 current_nonce 发送交易
682
+ data, tx_hash = send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
683
+ # 记录最后输出的结果
684
+ transaction_results.append(f"{address} | {data} | Transaction Hash: {tx_hash}")
685
+ # 交易成功后,手动增加 nonce 值
686
+ nonces[address] += 1
687
+ # 更新当前账户索引,确保索引始终在账户列表的范围内
688
+ current_account_index = (current_account_index + 1) % len(accounts)
689
+ # 暂停 3 秒
690
+ if sleep_3s:
691
+ time.sleep(3) # 暂停三秒
692
+ st.toast(f'所有任务已经完成。', icon='🎉')
693
+ # 庆祝动画
694
+ st.balloons()
695
+ # 显示所有交易的结果
696
+ st.code('\n'.join(transaction_results))
697
+
698
+ """
699
+
700
+ hf_name_code = r"""
701
+ # ethpen.com
702
+ # 最后更新日期:2023 年 8 月 18 日
703
+
704
+ # 在使用之前,敬请仔细阅读说明,感谢您的配合。
705
+ # 请务必访问 ethpen.com 官方网站。您可以确保这里的代码无恶意,安全地复制。
706
+ # 你只需要拥有一个 HuggingFace.co 账户。
707
+ # 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
708
+ # 我们建议您使用备用账号,并避免在账号中存放大额资金。
709
+ # 若您对此代码存有疑虑,建议您利用如 ChetGPT、Bard 或 Claude 等知名 AI 平台进行查询,以判断是否含有恶意代码。
710
+ # 请查看我们的例子 https://ethscriptions-name.hf.space。
711
+
712
+ # 导入运行代码所需要的库
713
+ import streamlit as st # streamlit app
714
+ from web3 import Web3 # 与以太坊交互的库
715
+ import hashlib # 用于数据哈希
716
+ import requests # 用于发送网络请求
717
+ import re # 用于正则表达式
718
+ import time # 用于时间相关
719
+
720
+
721
+ # 检查 ETH 地址是否有效
722
+ def is_valid_eth_address(address):
723
+ if re.match("^0x[0-9a-fA-F]{40}$", address):
724
+ return True
725
+ return False
726
+
727
+
728
+ # 检查 Ethereum 私钥是否有效
729
+ def is_valid_eth_private_key(private_key):
730
+ if re.match("^[0-9a-fA-F]{64}$", private_key):
731
+ return True
732
+ return False
733
+
734
+
735
+ # 验证输入的铭文文本是否含有空格和换行符,而且字母全部为小写
736
+ def validate_input(data_str):
737
+ if re.search(r'[A-Z\s\n]', data_str): # 查找大写字母、空格或换行符
738
+ return False
739
+ return True
740
+
741
+
742
+ # 分隔文本函数
743
+ def split_and_append(ethscriptions_str, name_selected_option):
744
+ separators = [' ', '\n', ',']
745
+ split_texts = [ethscriptions_str] # 初始时只有一个完整文本
746
+
747
+ for sep in separators:
748
+ pieces = []
749
+ for text in split_texts:
750
+ pieces.extend(text.split(sep))
751
+ split_texts = pieces
752
+
753
+ # 移除空字符串
754
+ split_texts = [text.strip() + name_selected_option for text in split_texts if text.strip() != '']
755
+
756
+ return split_texts
757
+
758
+
759
+ # 把文字转换成 16 ��制
760
+ def text_to_hex(text):
761
+ return ''.join(format(ord(char), '02x') for char in text)
762
+
763
+
764
+ # 使用sha256算法计算哈希
765
+ def sha256(input_string):
766
+ sha256 = hashlib.sha256()
767
+ sha256.update(input_string.encode('utf-8'))
768
+ return sha256.hexdigest()
769
+
770
+
771
+ # 使用 Ethscriptions API(主网)检查某个铭文是否已题写
772
+ def check_content_exists(sha):
773
+ # 定义请求的网址
774
+ endpoint = f"/ethscriptions/exists/{sha}"
775
+ response = requests.get('https://mainnet-api.ethscriptions.com/api' + endpoint)
776
+ # 如果返回状态码是200,说明请求成功,然后返回结果(Ture or False)
777
+ if response.status_code == 200:
778
+ return response.json()['result']
779
+
780
+
781
+ # 发送自己到自己 0ETH 的交易
782
+ def send_transaction(w3, account_address, private_key, chain_id, gas_price, input_data, current_nonce):
783
+
784
+ # 设置交易的相关信息
785
+ tx = {
786
+ 'chainId': chain_id, # 网络 ID
787
+ 'gas': 25000, # 如果交易 gas 过低,可适当调高
788
+ 'gasPrice': gas_price, # gas 的价格
789
+ 'nonce': current_nonce,
790
+ 'to': account_address, # 接收地址为自己
791
+ 'value': 0, # 金额为 0ETH
792
+ 'data': text_to_hex(input_data), # 铭文内容
793
+ }
794
+
795
+ # 用私钥签名这个交易
796
+ signed_tx = w3.eth.account.sign_transaction(tx, private_key)
797
+ # 发送签名后的交易并获取交易哈希
798
+ tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
799
+ # 打印结果信息
800
+ st.toast(f'{input_data}', icon='✅')
801
+ # 返回铭文还有交易哈希
802
+ return input_data, tx_hash.hex()
803
+
804
+ # 网页前端显示
805
+ # 网页标题
806
+ st.markdown('# [ethpen.com](https://ethpen.com) 域名铭文批量题写')
807
+ # 提醒
808
+ st.info('''在使用之前,敬请仔细阅读说明,感谢您的配合。
809
+ - 请务必访问 **[ethpen.com](https://ethpen.com)** 官方网站。您可以确保这里的代码无恶意,安全地复制。
810
+ - 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
811
+ - 我们建议您使用备用账号,并避免在账号中存放大额资金。
812
+ - 若您对此代码存有疑虑,建议您利用如 [ChetGPT](https://chat.openai.com/)、[Bard](https://bard.google.com/) 或 [Claude](https://claude.ai/) 等知名 AI 平台进行查询,以判断是否含有恶意代码。
813
+ ''')
814
+
815
+ # 连接的网络 ID。比如说,1 代表主网络,5 代表 Goerli 测试网络,11155111 代表 Sepolia 测试网络,如果你不放心,可以先用测试网试试。
816
+ net_options = {
817
+ '1': 'Mainnet',
818
+ '5': 'Goerli',
819
+ '11155111': 'Sepolia'
820
+ }
821
+ selected_option = st.selectbox(
822
+ '**网络 ID**',
823
+ list(net_options.keys()),
824
+ format_func=lambda x: f"{x} ({net_options[x]})"
825
+ )
826
+ chain_id = int(selected_option)
827
+
828
+ # 这里配置 Ethereum PRC URL,如果你没有,请到 infura.io 或者 alchemy.com 申请一个免费的 API
829
+ token_eth_prc_url = st.text_input(
830
+ f'**Ethereum PRC 链接**:选填,你可以去 [infura.io](https://app.infura.io/) 或者 [alchemy.com](https://alchemy.com/) 免费申请一个',
831
+ f'https://{net_options[str(chain_id)]}.infura.io/v3/eab7f935b9af45e1a54f7d7ed06c5206')
832
+ w3 = Web3(Web3.HTTPProvider(f'{token_eth_prc_url}'))
833
+ # 初始化当前账户索引为 0
834
+ current_account_index = 0
835
+ # 收集和显示所有交易的结果
836
+ transaction_results = []
837
+ # 创建账户列表
838
+ accounts = []
839
+ # 使用字典来跟踪每个地址的nonce
840
+ nonces = {}
841
+
842
+ # 启用多账户操作
843
+ if st.checkbox(f'启用**多账户**操作'):
844
+ # 多账户的文本框
845
+ account_list = st.text_area(f'输入多个 **ETH 地址及其对应的私钥**,用英文逗号分隔(,),如下:地址,私钥')
846
+ if account_list: # 如果账户列表有内容
847
+ for line in account_list.split('\n'): # 根据换行符划分账户
848
+ if ',' in line: # 检查是否包含逗号
849
+ address, key = line.split(',') # 分开地址和私钥
850
+ if is_valid_eth_address(address) and is_valid_eth_private_key(key): # 验证地址和私钥
851
+ current_nonce = w3.eth.get_transaction_count(address) # 获取地址的 nonce
852
+ nonces[address] = current_nonce # 记录地址的 nonce
853
+ accounts.append((address.strip(), key.strip())) # 保存地址和私钥还有 nonce
854
+ else:
855
+ st.error(f"地址 {address} 或私钥 {key} 无效,请检查!")
856
+ st.stop()
857
+ else:
858
+ st.error(f"输入格式错误,请确保每行包含一个地址和一个私钥,并使用英文逗号分隔(,)。错误行:**{line}**")
859
+ st.stop()
860
+ else:
861
+ account_address = st.text_input('填写你的 **ETH 地址**:')
862
+ private_key = st.text_input('填写你的 **ETH 地址对应的私钥**:', type="password")
863
+ if account_address and private_key: # 如果地址和私钥有内容
864
+ if is_valid_eth_address(account_address) and is_valid_eth_private_key(private_key): # 验证地址和私钥
865
+ current_nonce = w3.eth.get_transaction_count(account_address) # 获取地址的 nonce
866
+ nonces[account_address] = current_nonce # 记录地址的 nonce
867
+ accounts.append((account_address.strip(), private_key.strip())) # 保存地址和私钥还有 nonce
868
+ else:
869
+ st.error("地址或私钥无效,请检查!")
870
+ st.stop()
871
+
872
+ # 配置铭文文本
873
+ ethscriptions_str = st.text_area(f'输入**多个域名铭文或其他**,可以用空格、换行符、英文逗号(,)分开,不要带 data:, 前缀,不要带域名后缀')
874
+ name_options = ["自定义", ".eth", ".eths", ".tree", ".honk", ".etch"]
875
+ name_selected_option = st.selectbox(f'选择**域名后缀**', name_options)
876
+ if name_selected_option == '自定义':
877
+ name_selected_option = st.text_input('输入**自定义的域名**:')
878
+ # 以空格、换行符、英文逗号分隔文本并加上后缀
879
+ ethscription_list = split_and_append(ethscriptions_str, name_selected_option)
880
+
881
+ # 判断铭文文本里是否包含空格、换行符,而且所有的字母都必须为小写。
882
+ if not validate_input(''.join(ethscription_list)):
883
+ st.warning("**请注意**:通常代币铭文文本里不能包含空格、换行符,而且所有的字母都必须为小写。")
884
+
885
+ # 题写铭文之前检查该铭文有没有被题写
886
+ if st.checkbox(f'题写铭文之前**检查该铭文有没有被题写**'):
887
+ token_check = True
888
+ else:
889
+ token_check = False
890
+
891
+ # 每次交易成功后暂停 3 秒
892
+ if st.checkbox(f'每次交易完成后暂停 3 秒'):
893
+ sleep_3s = True
894
+ else:
895
+ sleep_3s = False
896
+
897
+ # 点击发送交易开始
898
+ if st.button(f'开始**发送交易**'):
899
+ if not accounts or not ethscriptions_str or not name_selected_option: # 检查是否留空
900
+ st.error(f'请正确谨慎地填写内容,每一项都**不应留空**。')
901
+ st.stop()
902
+ else:
903
+ st.toast('看起来你输入的内容均无没有问题!', icon='🥳')
904
+
905
+ st.toast(f'开始任务,需要题写的铭文总量为:{len(ethscription_list)}', icon='😎')
906
+
907
+ # 对代币铭文 id 进行循环
908
+ for name_str in ethscription_list:
909
+ # 使用当前账户发送交易,获取当前账户的 nonce
910
+ address, key = accounts[current_account_index]
911
+ # 获取 gas
912
+ gas_price = w3.eth.gas_price
913
+ # 得到完整的铭文文本
914
+ if not name_str.startswith('data:,'):
915
+ input_data = f'data:,{name_str}'
916
+
917
+ # 根据是否检查的开关进行
918
+ if token_check:
919
+ # 这里是开了检查后请求 Ethscriptions API
920
+ if check_content_exists(sha256(input_data)):
921
+ # 返回数据为 Ture,说明该铭文已经被题写,打印信息
922
+ st.toast(f'{input_data} 已经被题写!', icon='☹️')
923
+ else:
924
+ # 返回数据为 False,说明该铭文还没被题写,发送交易
925
+ # 使用 current_nonce 发送交易
926
+ data, tx_hash = send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
927
+ # 记录最后输出的结果
928
+ transaction_results.append(f"{address} | {data} | Transaction Hash: {tx_hash}")
929
+ # 交易成功后,手动增加 nonce 值
930
+ nonces[address] += 1
931
+ else:
932
+ # 这里是未开检查后直接发送交易
933
+ # 使用 current_nonce 发送交易
934
+ data, tx_hash = send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
935
+ # 记录最后输出的结果
936
+ transaction_results.append(f"{address} | {data} | Transaction Hash: {tx_hash}")
937
+ # 交易成功后,手动增加 nonce 值
938
+ nonces[address] += 1
939
+ # 更新当前账户索引,确保索引始终在账户列表的范围内
940
+ current_account_index = (current_account_index + 1) % len(accounts)
941
+ # 暂停 3 秒
942
+ if sleep_3s:
943
+ time.sleep(3) # 暂停三秒
944
+ st.toast(f'所有任务已经完成。', icon='🎉')
945
+ # 庆祝动画
946
+ st.balloons()
947
+ # 显示所有交易的结果
948
+ st.code('\n'.join(transaction_results))
949
+
950
+ """
951
+
952
+ my_style = '''
953
+ <style>
954
+ .tag {
955
+ display: inline-block;
956
+ padding: 2px 6px;
957
+ background-color: #f2f2f2; /* 默认的背景颜色 */
958
+ border-radius: 5px; /* 圆角效果 */
959
+ margin: 0 2px;
960
+ transition: background-color 0.3s; /* 平滑的颜色过渡效果 */
961
+ }
962
+
963
+ .tag:hover {
964
+ background-color: #cffd51; /* 鼠标经过时的背景颜色 */
965
+ }
966
+
967
+ .tag:active {
968
+ background-color: #cffd51; /* 鼠标按下时的背景颜色 */
969
+ }
970
+ </style>
971
+ '''
972
+
973
+
974
+ # 图片Base64
975
+ def image_to_base64(img_path):
976
+ with open(img_path, "rb") as image_file:
977
+ return base64.b64encode(image_file.read()).decode()
978
+
979
+
980
+ # 验证代币铭文函数
981
+ def is_valid_eths(data, p, tick, id, amt):
982
+ # 构建匹配1到id-1的正则表达式
983
+ pattern_range = "|".join([str(i) for i in range(1, id)])
984
+ # 使用 f-string 插入参数到正则表达式
985
+ pattern = rf'^data:,{{"p":"{p}","op":"mint","tick":"{tick}","id":"({pattern_range}|{id})","amt":"{amt}"}}$'
986
+ return bool(re.match(pattern, data))
987
+
988
+
989
+ # 文本转换到十六进制
990
+ def text_to_hex(text):
991
+ return ''.join(format(ord(char), '02x') for char in text)
992
+
993
+
994
+ # str SHA256
995
+ def sha256(input_string):
996
+ sha256 = hashlib.sha256()
997
+ sha256.update(input_string.encode('utf-8'))
998
+ return sha256.hexdigest()
999
+
1000
+
1001
+ # 根据 TX 获取 input data
1002
+ def get_input_data(tx_hash):
1003
+ endpoint = f"https://mainnet.infura.io/v3/{infura_api_key}"
1004
+ headers = {
1005
+ "Content-Type": "application/json",
1006
+ }
1007
+ data = {
1008
+ "jsonrpc": "2.0",
1009
+ "id": 1,
1010
+ "method": "eth_getTransactionByHash",
1011
+ "params": [tx_hash]
1012
+ }
1013
+ eth_transaction = requests.post(endpoint, headers=headers, data=json.dumps(data))
1014
+ transaction_data = eth_transaction.json()
1015
+ return transaction_data['result']['input']
1016
+
1017
+
1018
+ # 获取所有的 ethscriptions
1019
+ def get_all_ethscriptions(page=None, per_page=None, sort_order=None):
1020
+ endpoint = "/ethscriptions"
1021
+ params = {
1022
+ "page": page, # 页码
1023
+ "per_page": per_page, # 每页的数量
1024
+ "sort_order": sort_order # 排序顺序
1025
+ }
1026
+ response = requests.get(BASE_URL + endpoint, params=params)
1027
+ return response.json()
1028
+
1029
+
1030
+ # 根据地址获取 ethscriptions
1031
+ def get_ethscriptions_by_address(address):
1032
+ all_ethscriptions = []
1033
+ page = 1
1034
+ per_page = 100
1035
+ while True:
1036
+ endpoint = f"/ethscriptions/owned_by/{address}"
1037
+ params = {
1038
+ "page": page,
1039
+ "per_page": per_page,
1040
+ "sort_order": 'asc'
1041
+ }
1042
+ response = requests.get(BASE_URL + endpoint, params=params)
1043
+ if response.status_code != 200:
1044
+ print(f"Error fetching data: {response.text}")
1045
+ break
1046
+ ethscriptions = response.json()
1047
+ all_ethscriptions.extend(ethscriptions)
1048
+ if len(ethscriptions) < per_page:
1049
+ break
1050
+ page += 1
1051
+ return all_ethscriptions
1052
+
1053
+
1054
+ # 使用ID或数字获取特定的 ethscription
1055
+ def get_specific_ethscription(ethscription_identifier):
1056
+ endpoint = f"/ethscriptions/{ethscription_identifier}"
1057
+ response = requests.get(BASE_URL + endpoint)
1058
+ return response.json()
1059
+
1060
+
1061
+ # 获取特定 ethscription 的数据
1062
+ def get_ethscription_data(ethscription_identifier):
1063
+ endpoint = f"/ethscriptions/{ethscription_identifier}/data"
1064
+ response = requests.get(BASE_URL + endpoint)
1065
+ return response.json()
1066
+
1067
+
1068
+ # 使用 SHA256 值检查内容是否已被 ethscribed
1069
+ def check_content_exists(sha):
1070
+ endpoint = f"/ethscriptions/exists/{sha}"
1071
+ response = requests.get(BASE_URL + endpoint)
1072
+ if response.status_code == 200:
1073
+ return response.json()
1074
+
1075
+
1076
+ # 确定索引器是否落后
1077
+ def get_block_status():
1078
+ endpoint = "/block_status"
1079
+ response = requests.get(BASE_URL + endpoint)
1080
+ return response.json()
1081
+
1082
+
1083
+ # 获取 $eths 价格
1084
+ def get_eths_price():
1085
+ params = {
1086
+ 'category': 'token',
1087
+ 'collectionName': 'erc-20 eths',
1088
+ }
1089
+
1090
+ response = requests.get(
1091
+ 'https://www.etch.market/api/markets/collections/details',
1092
+ params=params
1093
+ )
1094
+ if response.status_code == 200:
1095
+ response = response.json()
1096
+ if response['message'] == 'success':
1097
+ return response['data']
1098
+ return {} # 返回一个空字典作为默认值
1099
+
1100
+
1101
+ # 从 etch.market 那里获取用户地址代币余额
1102
+ def get_etch_token_amt():
1103
+ params = {
1104
+ 'category': 'token',
1105
+ 'tokenQuery': '',
1106
+ }
1107
+
1108
+ response = requests.get(
1109
+ 'https://www.etch.market/api/markets/ethscriptions/collections/0x59724739940777947c56C4f2f2C9211cd5130FEf',
1110
+ params=params
1111
+ )
1112
+ if response.status_code == 200:
1113
+ response = response.json()
1114
+ if response['message'] == 'success':
1115
+ return response['data']
1116
+ return {} # 返回一个空字典作为默认值
1117
+
1118
+
1119
+ # 获取 $eths 质押数据
1120
+ def get_eths_staking():
1121
+ response = requests.get('https://www.etch.market/api/staking/statistics/erc-20%20eths')
1122
+ if response.status_code == 200:
1123
+ response = response.json()
1124
+ if response['message'] == 'success':
1125
+ return response['data']
1126
+ return {} # 返回一个空字典作为默认值
1127
+
1128
+
1129
+ st.set_page_config(page_title='EthPen - 以太之笔', page_icon='🖊️', initial_sidebar_state="collapsed")
1130
+
1131
+ # 首页
1132
+ st.markdown(
1133
+ f'# <a href="https://ethpen.com" target="_self"><img src="data:image/svg+xml;base64,{image_to_base64(os.path.join("img", "ethpen_logo.svg"))}" alt="Image" width="64px" height="64px" style="border-radius: 8px;"/></a> EthPen - 以太之笔',
1134
+ unsafe_allow_html=True)
1135
+ st.markdown('')
1136
+ # 介绍
1137
+ st.markdown(
1138
+ f'欢迎踏足 EthPen - 以太之笔!这里汇聚了一系列关于 Ethscriptions 的精细工具集,无论是单一查询、铭文题写��还是批量检索、编码题写,乃至深入的教程导引,以太之笔都将助您铭文题写如飞。我们立志推广 Ethscriptions 的宏大理念,期望 $eths 翱翔于星空,与月相伴!若您携手建议或创意,我们热切期待您的声音。',
1139
+ unsafe_allow_html=True)
1140
+ st.markdown(f'### 广告位')
1141
+ # 广告位图片
1142
+ st.markdown(
1143
+ f'<a href="https://twitter.com/EtchMarket/status/1694024108672245953" target="_blank"><img src="data:image/jpeg;base64,{image_to_base64(os.path.join("img", "ad.jpg"))}" alt="Image" style="max-width: 100%; width: 100%; height: auto; border-radius: 10px; display: block;"/></a>',
1144
+ unsafe_allow_html=True)
1145
+ st.markdown(f'> 拆分方案现在面向所有人推出!让我们一起加入权益挖矿的浪潮,并分享50%的月度服务费。')
1146
+ st.markdown("### 工具箱专区")
1147
+
1148
+ # st.expander
1149
+ search_rune_expander = st.expander("查询 Ethscriptions")
1150
+ create_rune_expander = st.expander("题写 Ethscriptions")
1151
+ token_no_code_expander = st.expander("一键式铭文批量题写,无需编码知识!")
1152
+ trend_expander = st.expander("潮流动态")
1153
+ help_expander = st.expander("教程帮助")
1154
+
1155
+ # 查询铭文页面
1156
+ search_rune_expander.info(
1157
+ f"铭文数据来自 [Ethscriptions](https://ethscriptions.com/) 官方网站,当前索引器状态落后: {get_block_status()['blocks_behind']} 个区块。")
1158
+ search_rune_expander.markdown("##### 查询 ETH 地址所属铭文")
1159
+ user_address = search_rune_expander.text_input('输入 ETH 地址:', '')
1160
+
1161
+ if search_rune_expander.button('🔍 查询', key='查询铭文'):
1162
+ # 检查ETH地址
1163
+ pattern = "^0x[a-fA-F0-9]{40}$"
1164
+ if re.match(pattern, user_address):
1165
+ data = get_ethscriptions_by_address(user_address)
1166
+ if not data:
1167
+ search_rune_expander.info(
1168
+ "该地址没有任何铭文,或许是区块暂时没同步过来,如果你不确定,请前往 Ethscriptions 官网再次查询!")
1169
+ else:
1170
+ token_total = 0
1171
+ for token in token_list:
1172
+ for ethscriptions in data:
1173
+ if is_valid_eths(ethscriptions['content_uri'], token['p'], token['tick'], token['id'],
1174
+ token['amt']):
1175
+ input_data_str = json.loads(ethscriptions['content_uri'][6:])
1176
+ token_total = token_total + int(input_data_str['amt'])
1177
+ search_rune_expander.success(f"${token['tick']} 有效总量为:{token_total}")
1178
+ token_total = 0
1179
+ search_rune_expander.warning(
1180
+ f"只统计 etch.market 流动性较高的资产,etch.market 上架的代币不计算在内,详细更多的信息请点击[这里](https://ethscriptions.com/{user_address})")
1181
+ else:
1182
+ search_rune_expander.error("输入的 ETH 地址不正确!")
1183
+
1184
+ search_rune_expander.markdown("##### 查询铭文的完整信息")
1185
+ ethscriptions_str = search_rune_expander.text_input('输入完整的铭文文本:', '')
1186
+ if search_rune_expander.button('🔍 查询', key='查询信息'):
1187
+ if not ethscriptions_str.startswith('data:,'):
1188
+ ethscriptions_str = f'data:,{ethscriptions_str}'
1189
+ ethscriptions_all_str = sha256(ethscriptions_str)
1190
+ ethscriptions_data = check_content_exists(ethscriptions_all_str)
1191
+ if ethscriptions_data['result']:
1192
+ search_rune_expander.markdown(f'###### :green[{ethscriptions_str}] 相关信息如下:')
1193
+ selected_data = {
1194
+ '当前拥有者': ethscriptions_data["ethscription"]["current_owner"],
1195
+ '题写时间': ethscriptions_data["ethscription"]["creation_timestamp"],
1196
+ '铭文编号': f'#{ethscriptions_data["ethscription"]["ethscription_number"]}',
1197
+ '铭文完整内容': ethscriptions_data["ethscription"]["content_uri"],
1198
+ }
1199
+ search_rune_expander.json(selected_data)
1200
+ else:
1201
+ search_rune_expander.markdown(f'###### :green[{ethscriptions_str}] 铭文还没被题写!复制下方文本前去题写。')
1202
+ search_rune_expander.code(f'{text_to_hex(ethscriptions_str)}', line_numbers=False)
1203
+
1204
+ # 批量查询铭文是否被存在
1205
+ runes = []
1206
+ search_rune_expander.markdown("##### 批量查询铭文是否被题写")
1207
+ search_rune_expander.markdown(r'''
1208
+ 1. **查域名**:可以用空格和换行符还有英文逗号(,)分开,不要带前缀 data:,
1209
+ 2. **查代币**:需要查询的代币铭文内容变动的部分文本如 id 请用 "@#" 代替,例如:`data:,{"p":"erc-20","op":"mint","tick":"eths","id":"@#","amt":"1000"}`
1210
+ 3. **查纯文本**:可任意填写,用空格和换行符还有英文逗号(,)分开''')
1211
+ input_content = search_rune_expander.text_area(f'输入铭文文本:')
1212
+ search_type = search_rune_expander.radio('选择查询类型:', ['查域名', '查代币', '查纯文本'],
1213
+ label_visibility="collapsed", horizontal=True, index=2)
1214
+ if search_type == '查域名':
1215
+ search_dotname = search_rune_expander.text_input('填写域名后缀:')
1216
+ elif search_type == '查代币':
1217
+ search_token_min_id = search_rune_expander.number_input(f'填写代币铭文范围的**最小 ID(id)**:', min_value=1, value=1,
1218
+ step=1)
1219
+ search_token_max_id = search_rune_expander.number_input(f'填写代币铭文范围的**最大 ID(id)**:', value=10, step=1)
1220
+
1221
+ if search_rune_expander.button('🔍 查询', key='批量查询铭文'):
1222
+ runes = re.split(r'[\s,]+', input_content)
1223
+ # 过滤掉空或仅包含空白字符的项
1224
+ runes = [r for r in runes if r.strip() != '']
1225
+ if search_type == '查域名':
1226
+ runes = [r + search_dotname for r in runes]
1227
+ elif search_type == '查代币':
1228
+ token_runes = []
1229
+ if len(runes) != 1 and '@#' in input_content:
1230
+ for the_id in range(search_token_min_id, search_token_max_id + 1):
1231
+ token_runes.append(input_content.replace('@#', str(the_id)))
1232
+ else:
1233
+ st.stop()
1234
+ runes = token_runes
1235
+ # 创建一个空的结果列表
1236
+ results = []
1237
+ # 循环遍历每一个铭文并查询其存在状态
1238
+ for rune in runes:
1239
+ if not rune.startswith('data:,'):
1240
+ rune = f'data:,{rune}'
1241
+ sha_value = sha256(rune)
1242
+ response_data = check_content_exists(sha_value)
1243
+
1244
+ # 根据返回的result,得到真或者假
1245
+ exists = "已题写" if response_data['result'] else "未题写"
1246
+ results.append([rune, exists])
1247
+
1248
+ # 使用 st.table 显示结果
1249
+ table_data = pd.DataFrame(results, columns=['铭文', '状态'])
1250
+
1251
+ # 根据状态生成一个辅助排序列
1252
+ table_data['sort_helper'] = table_data['状态'].apply(lambda x: 0 if x == "未题写" else 1)
1253
+
1254
+ # 使用辅助列进行排序
1255
+ table_data.sort_values(by='sort_helper', ascending=True, inplace=True)
1256
+
1257
+ # 删除辅助排序列
1258
+ table_data.drop(columns=['sort_helper'], inplace=True)
1259
+
1260
+ # 定义样式和生成带有专门类名的HTML表格
1261
+ table_style = """
1262
+ <style>
1263
+ .styled_table {
1264
+ width: 100%;
1265
+ border-collapse: collapse;
1266
+ border-radius: 8px;
1267
+ overflow: hidden; /* Ensures border-radius applies to table */
1268
+ }
1269
+ .styled_table th, .styled_table td {
1270
+ border: 1px solid #ddd;
1271
+ padding: 8px;
1272
+ text-align: left;
1273
+ }
1274
+ .styled_table th {
1275
+ background-color: #f2f2f2;
1276
+ color: black;
1277
+ }
1278
+ .styled_table tr:hover {
1279
+ background-color: #f5f5f5;
1280
+ }
1281
+ .styled_table td[status="已题写"] {
1282
+ background-color: #f2dede; /* Reddish */
1283
+ }
1284
+ .styled_table td[status="未题写"] {
1285
+ background-color: #dff0d8; /* Greenish */
1286
+ }
1287
+ </style>
1288
+ """
1289
+ search_rune_expander.markdown(table_style, unsafe_allow_html=True)
1290
+ table_html = table_data.to_html(index=False, classes='styled_table', border=0, escape=False,
1291
+ formatters=dict(状态=lambda x: f'<td status="{x}">{x}</td>'))
1292
+
1293
+ # 生成HTML表格但不为状态列添加特殊格式
1294
+ table_html = table_data.to_html(index=False, classes='styled_table', border=0, escape=False)
1295
+
1296
+ # 使用字符串替换为状态列添加特定属性
1297
+ table_html = table_html.replace('<td>已题写</td>', '<td status="已题写">已题写</td>')
1298
+ table_html = table_html.replace('<td>未题写</td>', '<td status="未题写">未题写</td>')
1299
+
1300
+ # 使用st.write输出带样式的HTML表格
1301
+ search_rune_expander.write(table_html, unsafe_allow_html=True)
1302
+ search_rune_expander.markdown('')
1303
+
1304
+ # 题写铭文页面
1305
+ create_rune_expander.markdown("##### 文本转换到十六进制")
1306
+ input_ethscriptions_str = create_rune_expander.text_input(
1307
+ '输入需要转换的文本,默认以 "data:," 开头,换行和回车字符不应出现。', '')
1308
+ if create_rune_expander.button('🔁 转换', key='文本转换到十六进制'):
1309
+ if not input_ethscriptions_str.startswith('data:,'):
1310
+ input_ethscriptions_str = f'data:,{input_ethscriptions_str}'
1311
+ input_ethscriptions_hex = text_to_hex(input_ethscriptions_str)
1312
+ create_rune_expander.markdown(f':green[{input_ethscriptions_str}] 转换到十六进制:')
1313
+ create_rune_expander.code(input_ethscriptions_hex, line_numbers=False)
1314
+ input_ethscriptions_sha = sha256(input_ethscriptions_str)
1315
+ ethscriptions_data = check_content_exists(input_ethscriptions_sha)
1316
+ if ethscriptions_data['result']:
1317
+ create_rune_expander.markdown(f'###### :green[{ethscriptions_str}] 相关信息如下:')
1318
+ selected_data = {
1319
+ '当前拥有者': ethscriptions_data["ethscription"]["current_owner"],
1320
+ '题写时间': ethscriptions_data["ethscription"]["creation_timestamp"],
1321
+ '铭文编号': f'#{ethscriptions_data["ethscription"]["ethscription_number"]}',
1322
+ '铭文完整内容': ethscriptions_data["ethscription"]["content_uri"],
1323
+ }
1324
+ create_rune_expander.json(selected_data)
1325
+ else:
1326
+ create_rune_expander.markdown(f'###### :green[{input_ethscriptions_str}] 铭文还没被题写!快前去题写吧。')
1327
+
1328
+ create_rune_expander.markdown("##### 批量自动题写铭文")
1329
+ create_rune_expander.info("""在使用之前,敬请仔细阅读说明,感谢您的配合。
1330
+ 1. 请务必访问 **[ethpen.com](https://ethpen.com)** 官方网站。您可以确保这里的代码无恶意,安全地复制。
1331
+ 2. 你只需要掌握一些 python 相关的基础。
1332
+ 3. 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
1333
+ 4. 我们建议您使用备用账号,并避免在账号中存放大额资金。
1334
+ 5. 若您对此代码存有疑虑,建议您利用如 [ChetGPT](https://chat.openai.com/)、[Bard](https://bard.google.com/) 或 [Claude](https://claude.ai/) 等知名 AI 平台进行查询,以判断是否含有恶意代码。
1335
+ 6. 如果你在使用的过程中发现 BUG 或者有什么想法和建议,欢迎与我联系。
1336
+ """)
1337
+ if create_rune_expander.button('🖨 打印代币代码', key='输出代币铭文 Python 代码'):
1338
+ create_rune_expander.code(python_token_code, 'python', line_numbers=False)
1339
+ if create_rune_expander.button('🖨 打印域名代码', key='输出域名铭文 Python 代码'):
1340
+ create_rune_expander.code(python_name_code, 'python', line_numbers=False)
1341
+
1342
+ # 全新不用懂代码的铭文批量题写页面
1343
+ token_no_code_expander.markdown("##### 安全的简易的批量自动题写铭文")
1344
+ token_no_code_expander.info("""在使用之前,敬请仔细阅读说明,感谢您的配合。
1345
+ 1. 请务必访问 **[ethpen.com](https://ethpen.com)** 官方网站。您可以确保这里的代码无恶意,安全地复制。
1346
+ 2. 你只需要拥有一个 [HuggingFace.co](https://huggingface.co) 账户。
1347
+ 3. 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
1348
+ 4. 我们建议您使用备用账号,并避免在账号中存放大额资金。
1349
+ 5. 若您对此代码存有疑虑,建议您利用如 [ChetGPT](https://chat.openai.com/)、[Bard](https://bard.google.com/) 或 [Claude](https://claude.ai/) 等知名 AI 平台进行查询,以判断是否含有恶意代码。
1350
+ 6. 请查看我们的例子 [token-example](https://huggingface.co/spaces/Ethscriptions/token) / [name-example](https://huggingface.co/spaces/Ethscriptions/name)。
1351
+ """)
1352
+ if token_no_code_expander.button('🖨️ 打印代币代码', key='输出 Token 铭文 Python 代码'):
1353
+ token_no_code_expander.markdown(
1354
+ f'**为 [HuggingFace.co](https://huggingface.co) 平台与 [Streamlit.io](https://streamlit.io/) 框架量身打造的代币铭文专业 Python 代码(app.py):**')
1355
+ token_no_code_expander.code(hf_token_code, 'python', line_numbers=False)
1356
+ token_no_code_expander.markdown(f"**依赖包清单(requirements.txt):**")
1357
+ token_no_code_expander.code('''
1358
+ Requests
1359
+ streamlit
1360
+ web3
1361
+ ''')
1362
+ if token_no_code_expander.button('🖨️ 打印域名代码', key='输出 Name 铭文 Python 代码'):
1363
+ token_no_code_expander.markdown(
1364
+ f'**为 [HuggingFace.co](https://huggingface.co) 平台与 [Streamlit.io](https://streamlit.io/) 框架量身打造的域名铭文专业 Python 代码(app.py):**')
1365
+ token_no_code_expander.code(hf_name_code, 'python', line_numbers=False)
1366
+ token_no_code_expander.markdown(f"**依赖包清单(requirements.txt):**")
1367
+ token_no_code_expander.code('''
1368
+ Requests
1369
+ streamlit
1370
+ web3
1371
+ ''')
1372
+
1373
+ # 潮流动态页面
1374
+ trend_expander.markdown("##### 开发中...")
1375
+
1376
+ # 教程帮助页面
1377
+ help_expander.markdown('##### 我不懂代码,怎么做到批量题写铭文?')
1378
+ # help_expander.markdown('##### 如何用 Metamask 题写 Ethscriptions 铭文?')
1379
+ # help_expander.markdown('##### 如何用 Metamask 在 etch.market 上购买 $eths?')
1380
+ # help_expander.markdown('##### 如何运行批量自动题写铭文 python 代码?')
1381
+ # help_expander.markdown(f'<iframe src="//player.bilibili.com/player.html?aid=787389115&bvid=BV1J14y1i7ap&cid=1237586207&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>', unsafe_allow_html=True)
1382
+
1383
+
1384
+ # 嵌入式SVG文本(以下只是示例,替换为你的SVG文本)
1385
+ twitter_svg = """
1386
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path fill="currentColor" d="M8 2H1l8.26 11.014L1.45 22H4.1l6.388-7.349L16 22h7l-8.608-11.478L21.8 2h-2.65l-5.986 6.886L8 2Zm9 18L5 4h2l12 16h-2Z"/></svg>
1387
+ """
1388
+ twitter_encoded_svg = base64.b64encode(twitter_svg.encode('utf-8')).decode('utf-8')
1389
+ telegram_svg = """
1390
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 256 256"><defs><linearGradient id="logosTelegram0" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2AABEE"/><stop offset="100%" stop-color="#229ED9"/></linearGradient></defs><path fill="url(#logosTelegram0)" d="M128 0C94.06 0 61.48 13.494 37.5 37.49A128.038 128.038 0 0 0 0 128c0 33.934 13.5 66.514 37.5 90.51C61.48 242.506 94.06 256 128 256s66.52-13.494 90.5-37.49c24-23.996 37.5-56.576 37.5-90.51c0-33.934-13.5-66.514-37.5-90.51C194.52 13.494 161.94 0 128 0Z"/><path fill="#FFF" d="M57.94 126.648c37.32-16.256 62.2-26.974 74.64-32.152c35.56-14.786 42.94-17.354 47.76-17.441c1.06-.017 3.42.245 4.96 1.49c1.28 1.05 1.64 2.47 1.82 3.467c.16.996.38 3.266.2 5.038c-1.92 20.24-10.26 69.356-14.5 92.026c-1.78 9.592-5.32 12.808-8.74 13.122c-7.44.684-13.08-4.912-20.28-9.63c-11.26-7.386-17.62-11.982-28.56-19.188c-12.64-8.328-4.44-12.906 2.76-20.386c1.88-1.958 34.64-31.748 35.26-34.45c.08-.338.16-1.598-.6-2.262c-.74-.666-1.84-.438-2.64-.258c-1.14.256-19.12 12.152-54 35.686c-5.1 3.508-9.72 5.218-13.88 5.128c-4.56-.098-13.36-2.584-19.9-4.708c-8-2.606-14.38-3.984-13.82-8.41c.28-2.304 3.46-4.662 9.52-7.072Z"/></svg>
1391
+ """
1392
+ telegram_encoded_svg = base64.b64encode(telegram_svg.encode('utf-8')).decode('utf-8')
1393
+ discord_svg = """
1394
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 256 256"><g fill="none"><rect width="256" height="256" fill="#5865F2" rx="60"/><g clip-path="url(#skillIconsDiscord0)"><path fill="#fff" d="M197.308 64.797a164.918 164.918 0 0 0-40.709-12.627a.618.618 0 0 0-.654.31c-1.758 3.126-3.706 7.206-5.069 10.412c-15.373-2.302-30.666-2.302-45.723 0c-1.364-3.278-3.382-7.286-5.148-10.412a.643.643 0 0 0-.655-.31a164.472 164.472 0 0 0-40.709 12.627a.583.583 0 0 0-.268.23c-25.928 38.736-33.03 76.52-29.546 113.836a.685.685 0 0 0 .26.468c17.106 12.563 33.677 20.19 49.94 25.245a.648.648 0 0 0 .702-.23c3.847-5.254 7.276-10.793 10.217-16.618a.633.633 0 0 0-.347-.881c-5.44-2.064-10.619-4.579-15.601-7.436a.642.642 0 0 1-.063-1.064a86.364 86.364 0 0 0 3.098-2.428a.618.618 0 0 1 .646-.088c32.732 14.944 68.167 14.944 100.512 0a.617.617 0 0 1 .655.08a79.613 79.613 0 0 0 3.106 2.436a.642.642 0 0 1-.055 1.064a102.622 102.622 0 0 1-15.609 7.428a.638.638 0 0 0-.339.889a133.075 133.075 0 0 0 10.208 16.61a.636.636 0 0 0 .702.238c16.342-5.055 32.913-12.682 50.02-25.245a.646.646 0 0 0 .26-.46c4.17-43.141-6.985-80.616-29.571-113.836a.506.506 0 0 0-.26-.238ZM94.834 156.142c-9.855 0-17.975-9.047-17.975-20.158s7.963-20.158 17.975-20.158c10.09 0 18.131 9.127 17.973 20.158c0 11.111-7.962 20.158-17.974 20.158Zm66.456 0c-9.855 0-17.974-9.047-17.974-20.158s7.962-20.158 17.974-20.158c10.09 0 18.131 9.127 17.974 20.158c0 11.111-7.884 20.158-17.974 20.158Z"/></g><defs><clipPath id="skillIconsDiscord0"><path fill="#fff" d="M28 51h200v154.93H28z"/></clipPath></defs></g></svg>
1395
+ """
1396
+ discord_encoded_svg = base64.b64encode(discord_svg.encode('utf-8')).decode('utf-8')
1397
+
1398
+ # 实际的社交链接
1399
+ twitter_link = "https://twitter.com/pztuya"
1400
+ telegram_link = "https://t.me/NervosCKB"
1401
+ discord_link = "https://discord.gg/ethscriptions"
1402
+
1403
+ # 关于页面
1404
+ eths_price_data = get_eths_price()
1405
+ st.markdown("### 关于")
1406
+ st.markdown(f'##### 什么是 Ethscriptions?', unsafe_allow_html=True)
1407
+ st.markdown(
1408
+ f'{my_style}<span class="tag"><a href="https://ethscriptions.com/" target="_blank" style="text-decoration: none;"><img src="data:image/jpeg;base64,{image_to_base64(os.path.join("img", "ethscriptions_logo_litto.png"))}" alt="Image" width="20px" height="20px" style="border-radius: 3px;"/> Ethscriptions </span></a>是一种新的在以太坊上创建和分享数字资产的方法,它通过使用交易 calldata 存储数据而不是智能合约来实现,这使其比 NFT 更为经济。它们是完全在链上、无需许可、抗审查的,并且其成本只是 NFT 的一小部分。',
1409
+ unsafe_allow_html=True)
1410
+ st.markdown('')
1411
+ st.markdown('##### 谁创造了 Ethscriptions?')
1412
+ st.markdown(
1413
+ f'首个 [Ethscription](https://ethscriptions.com/ethscriptions/0) 是在 2016 年创建的,但正式的协议是由 Tom Lehman,又名 <span class="tag"><a href="https://twitter.com/dumbnamenumbers" target="_blank" style="text-decoration: none;"><img src="data:image/jpeg;base64,{image_to_base64(os.path.join("img", "Middlemarch.jpg"))}" alt="Image" width="20px" height="20px" style="border-radius: 10px;"/> @Middlemarch</span></a> 开发的。除了比特币的铭文,他还受到了来自 Poly Network 黑客的著名的 “原型 - Ethscription” 的启发,你可以在[这笔交易](https://etherscan.io/tx/0x0ae3d3ce3630b5162484db5f3bdfacdfba33724ffb195ea92a6056beaa169490)中看到它。',
1414
+ unsafe_allow_html=True)
1415
+ st.markdown(
1416
+ f'- 快来加入 <span class="tag"><a href="https://discord.gg/ethscriptions" target="_blank" style="text-decoration: none;"><img src="data:image/svg+xml;base64,{discord_encoded_svg}" /> @ethscriptions</span></a>,与 Ethscriptions 一起成长!',
1417
+ unsafe_allow_html=True)
1418
+ st.markdown('##### Ethscriptions 上的龙头代币是?')
1419
+ st.markdown(
1420
+ f'毫无疑问,当自无愧,她必须是 Ethscriptions 上第一个代币 👉 <span class="tag"><a href="https://www.etch.market/market/token?category=token&collectionName=erc-20%20eths" target="_blank" style="text-decoration: none;"><img src="data:image/jpeg;base64,{image_to_base64(os.path.join("img", "eths_logo.png"))}" alt="Image" width="20px" height="20px"/> **eths**</span></a>',
1421
+ unsafe_allow_html=True)
1422
+
1423
+ # 查询eths_data表中所有数据
1424
+ c.execute('SELECT * FROM eths_data')
1425
+ # 获取所有结果
1426
+ eths_data = c.fetchall()
1427
+
1428
+ # 定义卡片样式
1429
+ eths_card_style = """
1430
+ <style>
1431
+ .card {
1432
+ border: 1px solid #e1e4e8;
1433
+ padding: 20px;
1434
+ border-radius: 15px;
1435
+ margin: -20px 0;
1436
+ }
1437
+
1438
+ .card p {
1439
+ margin-top: 7px;
1440
+ margin-bottom: 7px;
1441
+ }
1442
+
1443
+ .card h5 {
1444
+ margin-top: 10px;
1445
+ margin-bottom: -10px;
1446
+ }
1447
+
1448
+ .card a.button {
1449
+ display: inline-block;
1450
+ padding: 10px 15px;
1451
+ border: none;
1452
+ border-radius: 5px;
1453
+ background-color: #5bc43b;
1454
+ color: #fff;
1455
+ text-align: center;
1456
+ text-decoration: none;
1457
+ transition: background-color 0.3s;
1458
+ }
1459
+
1460
+ .card a.button:hover {
1461
+ background-color: #ccfd51;
1462
+ }
1463
+
1464
+ </style>
1465
+ """
1466
+ st.markdown(eths_card_style, unsafe_allow_html=True)
1467
+ # 创建卡片的HTML内容
1468
+ eths_card_content = f"""
1469
+ <div class="card">
1470
+ <img src="data:image/jpeg;base64,{image_to_base64(os.path.join("img", "eths_logo.jpeg"))}" alt="Image" style="max-width: 100%; width: 100%; height: auto; border-radius: 10px; display: block;"/></a>
1471
+ <p></p>
1472
+ <div style="display: flex; align-items: center; gap: 10px;">
1473
+ <img src="data:image/jpeg;base64,{image_to_base64(os.path.join("img", "eths_logo.png"))}" alt="Image" width="40px" height="40px" />
1474
+ <div>
1475
+ <h3 style="margin: 0; margin-bottom: -35px; font-size: 30px;">Ethscriptions eths</h3>
1476
+ <p style="margin: 0; font-size: 40px;"><strong>${eths_data[0][2]:.2f}</strong></p>
1477
+ </div>
1478
+ </div>
1479
+ <p>市值:<span class="tag">${eths_data[0][3]:,.0f}</span></p>
1480
+ <p>总量:<span class="tag">21,000,000</span></p>
1481
+ <p>24h 交易量:<span class="tag">${eths_data[0][5]:,.0f}</span></p>
1482
+ <h5>INFO</h5>
1483
+ <p>官网:None</p>
1484
+ <p>浏览器:<span class="tag"><a href="https://ethscriptions.com/" target="_blank" style="text-decoration: none;"><img src="data:image/jpeg;base64,{image_to_base64(os.path.join("img", "ethscriptions_logo_litto.png"))}" alt="Image" width="20px" height="20px" style="border-radius: 3px;"/> Ethscriptions</a></span></p>
1485
+ <p>Ethscription ID:<span class="tag"><a href="https://ethscriptions.com/ethscriptions/0x4636542d00d8075360d0303eb224c4ffb638169c23d6308aace55249b0bed2e4" target="_blank" style="text-decoration: none;"><img src="data:image/jpeg;base64,{image_to_base64(os.path.join("img", "ethscriptions_logo_litto.png"))}" alt="Image" width="20px" height="20px" style="border-radius: 3px;"/> 0x463654......bed2e4</a></span></p>
1486
+ <p>部署时间:<span class="tag">2023/06/18 05:46:11</span></p>
1487
+ <p>公链:<span class="tag">Ethereum Ethscriptions</span></p>
1488
+ <p>持有人数:<span class="tag">{eths_data[0][4]:,.0f}</span></p>
1489
+ <p>社交:<span class="tag"><a href="https://twitter.com/ethscriptions" target="_blank" style="text-decoration: none;"><img src="data:image/svg+xml;base64,{twitter_encoded_svg}" /> @ethscriptions</a></span><span class="tag"><a href="https://discord.gg/ethscriptions" target="_blank" style="text-decoration: none";><img src="data:image/svg+xml;base64,{discord_encoded_svg}" /> @ethscriptions</a></span></p>
1490
+ <h5>Staking</h5>
1491
+ <p>质押总量:<span class="tag">{eths_data[0][6]:,.0f} $eths</span></p>
1492
+ <p>质押人数:<span class="tag">{eths_data[0][7]:,.0f}</span></p>
1493
+ <p>TVL:<span class="tag">${eths_data[0][8]:,.0f}</span></p>
1494
+ <p><a href="https://www.etch.market/market/token?category=token&collectionName=erc-20%20eths" target="_blank" class="button">立即买入 $eths</a></p>
1495
+ </div>
1496
+ """
1497
+ st.markdown(eths_card_content, unsafe_allow_html=True)
1498
+
1499
+ st.markdown('')
1500
+ st.markdown('##### 关于 ethpen.com 作者')
1501
+ st.markdown('大家好,我叫 pztuya,期待你们和我多多交流😊~')
1502
+
1503
+ st.markdown(f'''
1504
+ <span class="tag"><a href="https://twitter.com/pztuya" target="_blank" style="text-decoration: none;"><img src="data:image/svg+xml;base64,{twitter_encoded_svg}" /> @pztuya</a></span>
1505
+ <span class="tag"><a href="https://t.me/NervosCKB" target="_blank" style="text-decoration: none;"><img src="data:image/svg+xml;base64,{telegram_encoded_svg}" /> @NervosCKB</a></span>
1506
+ ''', unsafe_allow_html=True)
img/Middlemarch.jpg ADDED
img/ad.jpg ADDED
img/ad.png ADDED
img/ethpen_logo.svg ADDED
img/eths_logo.jpeg ADDED
img/eths_logo.jpg ADDED
img/eths_logo.png ADDED
img/ethscriptions_logo_litto.png ADDED
img/huggingface_logo.svg ADDED
logo/.DS_Store ADDED
Binary file (6.15 kB). View file
 
logo/favicon.png ADDED
logo/icon-512.png ADDED
logo/icon-57.png ADDED
logo/icon-60.png ADDED
logo/[email protected] ADDED
logo/icon-hdpi.png ADDED
logo/icon-ldpi.png ADDED
logo/icon-mdpi.png ADDED
logo/icon-xhdpi.png ADDED
logo/icon-xxhdpi.png ADDED
logo/splash-1125x2436.png ADDED
logo/splash-1242x2208.png ADDED
logo/splash-640x1136.png ADDED
pages/.DS_Store ADDED
Binary file (6.15 kB). View file
 
pages/1_🔍_批量查询铭文状态.py ADDED
@@ -0,0 +1,319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import re
3
+ import os
4
+ import sqlite3
5
+ import pandas as pd
6
+
7
+
8
+ # 获取当前文件目录
9
+ current_dir = os.path.dirname(__file__)
10
+ parent_dir = os.path.dirname(current_dir)
11
+ name_set_file = os.path.join(parent_dir, 'data', 'name_set.db')
12
+ name_set_conn = sqlite3.connect(name_set_file)
13
+ name_set_cursor = name_set_conn.cursor()
14
+
15
+ content_set = ''
16
+ check_type = ''
17
+
18
+ # 把文字转换成 16 进制
19
+ def text_to_hex(text):
20
+ return '0x' + ''.join(format(ord(char), '02x') for char in text)
21
+
22
+
23
+ def get_name_set_data(set_choose):
24
+ global content_set
25
+ name_set_cursor.execute(f"SELECT data FROM set_data WHERE name='{set_choose}'")
26
+ content_set = f'{name_set_cursor.fetchone()[0]}'
27
+
28
+
29
+ st.set_page_config(page_title="EthPen - 批量查询铭文状态", page_icon="🆔")
30
+
31
+ st.markdown(f'# EthPen - 批量查询铭文状态')
32
+ name_selected_option = st.radio("选择查询的类型:",
33
+ ['🔤纯文本', '🪙代币铭文', '🆔.eths', '🆔.eth', '🌲.tree', '🦛.honk', '🔄.etch', '🌐.com', '🥳.club'], index=0,
34
+ horizontal=True)
35
+
36
+ if name_selected_option == '🔤纯文本':
37
+ check_type = ''
38
+ if name_selected_option == '🪙代币铭文':
39
+ token_check = True
40
+ token_str = st.text_input('填写代币铭文文本(变动的部分文本如 id 请用 "@#" 代替):', 'data:,{"p":"erc-20","op":"mint","tick":"eths","id":"@#","amt":"1000"}')
41
+ col1, col2 = st.columns(2)
42
+ with col1:
43
+ token_min_id = st.number_input('填写最小 ID:', min_value=1, value=1, step=1)
44
+ with col2:
45
+ token_max_id = st.number_input('填写最大 ID:', min_value=2, value=21000, step=1)
46
+ token_str_list = []
47
+ if token_str != '' and '@#' in token_str:
48
+ for token_id in range(token_min_id, token_max_id + 1):
49
+ token_str_list.append(token_str.replace('@#', str(token_id)))
50
+ content_set = '\n'.join(token_str_list)
51
+ st.code(token_str_list[0], language="json", line_numbers=False)
52
+ content = st.text_area('只需简单输入或粘贴您想查询的铭文列表,或是一篇文章,即可轻松查询所有铭文的状态。', value=content_set)
53
+ else:
54
+ token_check = False
55
+ if name_selected_option == '🆔.eths':
56
+ check_type = '.eths'
57
+ if name_selected_option == '🆔.eth':
58
+ check_type = '.eth'
59
+ if name_selected_option == '🌲.tree':
60
+ check_type = '.tree'
61
+ if name_selected_option == '🦛.honk':
62
+ check_type = '.honk'
63
+ if name_selected_option == '🔄.etch':
64
+ check_type = '.etch'
65
+ if name_selected_option == '🌐.com':
66
+ check_type = '.com'
67
+ if name_selected_option == '🥳.club':
68
+ check_type = '.club'
69
+
70
+ if not token_check:
71
+ options = ["⌨️直接输入", "🔥热门", "🔢数字", "🖊️Emoji", "🔤字母", "📛名字", "💡其他", "📃导入文件"]
72
+
73
+ name_set = st.radio("选择系列(生成器):", options, index=0, disabled=token_check, horizontal=True)
74
+
75
+ if name_set:
76
+ if name_set == "⌨️直接输入":
77
+ content_set = ''
78
+ if name_set == "🔥热门":
79
+ hot_options = ["数字 1K", "稀有 4D", "数字 10K", "数字 100K"]
80
+ hot_name_set = st.radio("热门系列", hot_options, index=0, disabled=token_check, horizontal=True, label_visibility="collapsed")
81
+ if hot_name_set == '数字 1K':
82
+ get_name_set_data(hot_name_set)
83
+ if hot_name_set == '稀有 4D':
84
+ get_name_set_data(hot_name_set)
85
+ if hot_name_set == '数字 10K':
86
+ get_name_set_data(hot_name_set)
87
+ if hot_name_set == '数字 100K':
88
+ get_name_set_data(hot_name_set)
89
+
90
+ if name_set == "🔢数字":
91
+ digit_options = ["数字 1K", "稀有 4D", "数字 10K", "数字 100K"]
92
+ digit_name_set = st.radio("数字系列", digit_options, index=0, disabled=token_check, horizontal=True, label_visibility="collapsed")
93
+ if digit_name_set == '数字 1K':
94
+ get_name_set_data(digit_name_set)
95
+ if digit_name_set == '稀有 4D':
96
+ get_name_set_data(digit_name_set)
97
+ if digit_name_set == '数字 10K':
98
+ get_name_set_data(digit_name_set)
99
+ if digit_name_set == '数字 100K':
100
+ get_name_set_data(digit_name_set)
101
+
102
+ if name_set == "🖊️Emoji":
103
+ emoji_options = ["单个 Emoji", "Emoji 笑脸和人", "Emoji 动物和自然", "Emoji 食物和饮料", "Emoji 活动",
104
+ "Emoji 旅行和地点", "Emoji 物体", "Emoji 符号", "Emoji 旗帜", "Emoji99", "Emoji1K", "Emoji10K"]
105
+ emoji_name_set = st.radio("emoji系列", emoji_options, index=0, disabled=token_check, horizontal=True, label_visibility="collapsed")
106
+ if emoji_name_set == '单个 Emoji':
107
+ get_name_set_data(emoji_name_set)
108
+ if emoji_name_set == 'Emoji 笑脸和人':
109
+ get_name_set_data(emoji_name_set)
110
+ if emoji_name_set == 'Emoji 动物和自然':
111
+ get_name_set_data(emoji_name_set)
112
+ if emoji_name_set == 'Emoji 食物和饮料':
113
+ get_name_set_data(emoji_name_set)
114
+ if emoji_name_set == 'Emoji 活动':
115
+ get_name_set_data(emoji_name_set)
116
+ if emoji_name_set == 'Emoji 旅行和地点':
117
+ get_name_set_data(emoji_name_set)
118
+ if emoji_name_set == 'Emoji 物体':
119
+ get_name_set_data(emoji_name_set)
120
+ if emoji_name_set == 'Emoji 符号':
121
+ get_name_set_data(emoji_name_set)
122
+ if emoji_name_set == 'Emoji 旗帜':
123
+ get_name_set_data(emoji_name_set)
124
+ if emoji_name_set == 'Emoji99':
125
+ get_name_set_data(emoji_name_set)
126
+ if emoji_name_set == 'Emoji1K':
127
+ get_name_set_data(emoji_name_set)
128
+ if emoji_name_set == 'Emoji10K':
129
+ get_name_set_data(emoji_name_set)
130
+ if name_set == "🔤字母":
131
+ letter_options = ["四字母单词", "五字母单词", "助记词", "英语名词"]
132
+ letter_name_set = st.radio("字母系列", letter_options, index=0, disabled=token_check, horizontal=True, label_visibility="collapsed")
133
+ if letter_name_set == '四字母单词':
134
+ get_name_set_data(letter_name_set)
135
+ if letter_name_set == '五字母单词':
136
+ get_name_set_data(letter_name_set)
137
+ if letter_name_set == '助记词':
138
+ get_name_set_data(letter_name_set)
139
+ if letter_name_set == '英语名词':
140
+ get_name_set_data(letter_name_set)
141
+ if name_set == "📛名字":
142
+ full_name_options = ["全球姓氏", "全球名字", "百家姓", "美国姓氏", "美国男名", "美国女名", "宝可梦第一世代", "宝可梦",
143
+ "哈利波特", "星球大战", "魔力宝贝", "我的世界"]
144
+ full_name_set = st.radio("名字系列", full_name_options, index=0, disabled=token_check, horizontal=True, label_visibility="collapsed")
145
+ if full_name_set == '全球姓氏':
146
+ get_name_set_data(full_name_set)
147
+ if full_name_set == '全球名字':
148
+ get_name_set_data(full_name_set)
149
+ if full_name_set == '百家姓':
150
+ get_name_set_data(full_name_set)
151
+ if full_name_set == '美国姓氏':
152
+ get_name_set_data(full_name_set)
153
+ if full_name_set == '美国男名':
154
+ get_name_set_data(full_name_set)
155
+ if full_name_set == '美国女名':
156
+ get_name_set_data(full_name_set)
157
+ if full_name_set == '宝可梦第一世代':
158
+ get_name_set_data(full_name_set)
159
+ if full_name_set == '宝可梦':
160
+ get_name_set_data(full_name_set)
161
+ if full_name_set == '哈利波特':
162
+ get_name_set_data(full_name_set)
163
+ if full_name_set == '星球大战':
164
+ get_name_set_data(full_name_set)
165
+ if full_name_set == '魔力宝贝':
166
+ get_name_set_data(full_name_set)
167
+ if full_name_set == '我的世界':
168
+ get_name_set_data(full_name_set)
169
+ if name_set == "💡其他":
170
+ other_name_options = ["汉字", "24H 计时"]
171
+ other_name_set = st.radio("其他系列", other_name_options, index=0, disabled=token_check, horizontal=True, label_visibility="collapsed")
172
+ if other_name_set == '汉字':
173
+ get_name_set_data(other_name_set)
174
+ if other_name_set == '24H 计时':
175
+ get_name_set_data(other_name_set)
176
+ if name_set == "📃导入文件":
177
+ uploaded_file = st.file_uploader("上传文件", type=['txt', 'csv', 'xlsx'])
178
+
179
+ if uploaded_file is not None:
180
+ if uploaded_file.type not in ['text/plain', 'text/csv', 'application/vnd.ms-excel']:
181
+ st.error('文件类型不支持')
182
+ else:
183
+ # 读取上传的文件内容
184
+ uploaded_file_contents = uploaded_file.read().decode('utf-8')
185
+
186
+ # 将文件内容分割成列表,使用空格、换行符和逗号作为分隔符
187
+ separators = [' ', '\n', ',']
188
+ uploaded_file_contents_list = re.split('|'.join(map(re.escape, separators)), uploaded_file_contents)
189
+
190
+ # 在这里,file_contents_list 包含了分割后的文本元素
191
+ # 去除重复元素,将列表转换为集合,然后再转回列表
192
+ uploaded_unique_contents_list = list(set(uploaded_file_contents_list))
193
+ content_set = ' '.join(uploaded_unique_contents_list)
194
+
195
+ if not token_check:
196
+ if st.checkbox(f'自定义前后缀'):
197
+ col1, col2 = st.columns(2)
198
+ with col1:
199
+ custom_prefix = st.text_input("自定义前缀")
200
+ with col2:
201
+ if check_type == '':
202
+ suffix_check = False
203
+ else:
204
+ suffix_check = True
205
+ custom_suffix = st.text_input("自定义后缀", disabled=suffix_check)
206
+ else:
207
+ custom_prefix, custom_suffix = '', ''
208
+
209
+ if not token_check:
210
+ if st.checkbox(f'过滤器'):
211
+ col1, col2, col3, col4, col5, col6 = st.columns(6)
212
+ with col1:
213
+ start_with = st.text_input("以*开头", key='过滤器(可选)1')
214
+ with col2:
215
+ end_with = st.text_input("以*结尾", key='过滤器(可选)2')
216
+ with col3:
217
+ contain = st.text_input("包含*", key='过滤器(可选)3')
218
+ with col4:
219
+ no_contain = st.text_input("不包含*", key='过滤器(可选)4')
220
+ with col5:
221
+ min_length = st.text_input("最少长度", key='过滤器(可选)5')
222
+ with col6:
223
+ max_length = st.text_input("最大长度", key='过滤器(可选)6')
224
+
225
+ # 将过滤条件应用到原始 name_set 字符串列表
226
+ filtered_list = content_set.split() # 使用空格、换行符和逗号分隔字符串,得到列表
227
+
228
+ if start_with:
229
+ filtered_list = [item for item in filtered_list if item.startswith(start_with)]
230
+
231
+ if end_with:
232
+ filtered_list = [item for item in filtered_list if item.endswith(end_with)]
233
+
234
+ if contain:
235
+ filtered_list = [item for item in filtered_list if contain in item]
236
+
237
+ if no_contain:
238
+ filtered_list = [item for item in filtered_list if no_contain not in item]
239
+
240
+ if min_length:
241
+ filtered_list = [item for item in filtered_list if len(item) >= int(min_length)]
242
+
243
+ if max_length:
244
+ filtered_list = [item for item in filtered_list if len(item) <= int(max_length)]
245
+
246
+ # 将处理后的列表重新合并成字符串
247
+ content_set = ' '.join(filtered_list)
248
+
249
+ if not token_check:
250
+ content = st.text_area('只需简单输入或粘贴您想查询的铭文列表,或是一篇文章,即可轻松查询所有铭文的状态。', value=content_set)
251
+
252
+ if st.checkbox('隐藏已题写'):
253
+ hide_inscribed = True
254
+ else:
255
+ hide_inscribed = False
256
+
257
+ if st.button('🔎 查询', key='🔎 查询'):
258
+ all_items = []
259
+ names = []
260
+ if token_check:
261
+ for i in token_str_list:
262
+ names.append(i)
263
+ all_items.append(text_to_hex(i))
264
+ else:
265
+ if check_type == '':
266
+ names = re.split(r"\s+", content)
267
+ # names = list(set(names))
268
+ names = [custom_prefix + name + custom_suffix for name in names]
269
+ names = ["data:," + name if not name.startswith("data:,") else name for name in names]
270
+ for i in names:
271
+ if names is not 'data:,':
272
+ all_items.append(text_to_hex(i))
273
+ else:
274
+ names = re.split(r"\s+", content)
275
+ # names = list(set(names))
276
+ names = [custom_prefix + name + check_type for name in names]
277
+ names = ["data:," + name if not name.startswith("data:,") else name for name in names]
278
+
279
+ for i in names:
280
+ if names is not 'data:,':
281
+ all_items.append(text_to_hex(i))
282
+
283
+ ethscrptions_db_file = os.path.join(parent_dir, 'data', 'ethscriptions_data.db')
284
+
285
+ ethscriptions_conn = sqlite3.connect(ethscrptions_db_file)
286
+
287
+ ethscriptions_cursor = ethscriptions_conn.cursor()
288
+
289
+ result = []
290
+ for index in range(len(names)):
291
+ ethscriptions_cursor.execute("SELECT * FROM data WHERE data=?", (all_items[index],))
292
+ row = ethscriptions_cursor.fetchone()
293
+ if hide_inscribed:
294
+ if not row:
295
+ result.append({"铭文": names[index], "状态": "未题写", "十六进制数据": all_items[index]})
296
+ else:
297
+ if row:
298
+ result.append({"铭文": names[index], "状态": "已题写", "十六进制数据": all_items[index]})
299
+ else:
300
+ result.append({"铭文": names[index], "状态": "未题写", "十六进制数据": all_items[index]})
301
+
302
+ if result == []:
303
+ st.markdown(f'## ☹️ 你来迟了~')
304
+ else:
305
+ # 将结果转换为Pandas DataFrame
306
+ result_df = pd.DataFrame(result)
307
+ st.dataframe(result_df, use_container_width=True, hide_index=True)
308
+ # Convert DataFrame to CSV with proper encoding
309
+ csv_export = result_df.to_csv(index=False, encoding='utf-8')
310
+ # Add a download button for the DataFrame
311
+ st.download_button(
312
+ label="下载搜索结果",
313
+ data=csv_export,
314
+ file_name="ethpen_result_data.csv",
315
+ mime="text/csv"
316
+ )
317
+
318
+
319
+
pages/2_🆔_ 批量题写域名铭文.py ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ethpen.com
2
+ # 最后更新日期:2023 年 8 月 18 日
3
+
4
+ # 在使用之前,敬请仔细阅读说明,感谢您的配合。
5
+ # 请务必访问 ethpen.com 官方网站。您可以确保这里的代码无恶意,安全地复制。
6
+ # 你只需要拥有一个 HuggingFace.co 账户。
7
+ # 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
8
+ # 我们建议您使用备用账号,并避免在账号中存放大额资金。
9
+ # 若您对此代码存有疑虑,建议您利用如 ChetGPT、Bard 或 Claude 等知名 AI 平台进行查询,以判断是否含有恶意代码。
10
+ # 请查看我们的例子 https://ethscriptions-name.hf.space。
11
+
12
+ # 导入运行代码所需要的库
13
+ import streamlit as st # streamlit app
14
+ from web3 import Web3 # 与以太坊交互的库
15
+ import hashlib # 用于数据哈希
16
+ import requests # 用于发送网络请求
17
+ import re # 用于正则表达式
18
+ import time # 用于时间相关
19
+
20
+
21
+ # 检查 ETH 地址是否有效
22
+ def is_valid_eth_address(address):
23
+ if re.match("^0x[0-9a-fA-F]{40}$", address):
24
+ return True
25
+ return False
26
+
27
+
28
+ # 检查 Ethereum 私钥是否有效
29
+ def is_valid_eth_private_key(private_key):
30
+ if re.match("^[0-9a-fA-F]{64}$", private_key):
31
+ return True
32
+ return False
33
+
34
+
35
+ # 验证输入的铭文文本是否含有空格和换行符,而且字母全部为小写
36
+ def validate_input(data_str):
37
+ if re.search(r'[A-Z\s\n]', data_str): # 查找大写字母、空格或换行符
38
+ return False
39
+ return True
40
+
41
+
42
+ # 分隔文本函数
43
+ def split_and_append(ethscriptions_str, name_selected_option):
44
+ separators = [' ', '\n', ',']
45
+ split_texts = [ethscriptions_str] # 初始时只有一个完整文本
46
+
47
+ for sep in separators:
48
+ pieces = []
49
+ for text in split_texts:
50
+ pieces.extend(text.split(sep))
51
+ split_texts = pieces
52
+
53
+ # 移除空字符串
54
+ split_texts = [text.strip() + name_selected_option for text in split_texts if text.strip() != '']
55
+
56
+ return split_texts
57
+
58
+
59
+ # 把文字转换成 16 进制
60
+ def text_to_hex(text):
61
+ return ''.join(format(ord(char), '02x') for char in text)
62
+
63
+
64
+ # 使用sha256算法计算哈希
65
+ def sha256(input_string):
66
+ sha256 = hashlib.sha256()
67
+ sha256.update(input_string.encode('utf-8'))
68
+ return sha256.hexdigest()
69
+
70
+
71
+ # 使用 Ethscriptions API(主网)检查某个铭文是否已题写
72
+ def check_content_exists(sha):
73
+ # 定义请求的网址
74
+ endpoint = f"/ethscriptions/exists/{sha}"
75
+ response = requests.get('https://mainnet-api.ethscriptions.com/api' + endpoint)
76
+ # 如果返回状态码是200,说明请求成功,然后返回结果(Ture or False)
77
+ if response.status_code == 200:
78
+ return response.json()['result']
79
+
80
+
81
+ # 发送自己到自己 0ETH 的交易
82
+ def send_transaction(w3, account_address, private_key, chain_id, gas_price, input_data, current_nonce):
83
+
84
+ # 设置交易的相关信息
85
+ tx = {
86
+ 'chainId': chain_id, # 网络 ID
87
+ 'gas': 25000, # 如果交易 gas 过低,可适当调高
88
+ 'gasPrice': gas_price, # gas 的价格
89
+ 'nonce': current_nonce,
90
+ 'to': account_address, # 接收地址为自己
91
+ 'value': 0, # 金额为 0ETH
92
+ 'data': text_to_hex(input_data), # 铭文内容
93
+ }
94
+
95
+ # 用私钥签名这个交易
96
+ signed_tx = w3.eth.account.sign_transaction(tx, private_key)
97
+ # 发送签名后的交易并获取交易哈希
98
+ tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
99
+ # 打印结果信息
100
+ st.toast(f'{input_data}', icon='✅')
101
+ # 返回铭文还有交易哈希
102
+ return input_data, tx_hash.hex()
103
+
104
+ # 网页前端显示
105
+ # 网页标题
106
+ st.markdown('# [ethpen.com](https://ethpen.com) 域名铭文批量题写')
107
+
108
+ # 提醒
109
+ st.info('''##### 在使用之前,敬请仔细阅读说明,感谢您的配合。
110
+ - 我们的网站已经全部开源,此页面的代码为:[3_🆔_批量题写域名铭文.py](https://huggingface.co/spaces/Ethscriptions/eths/blob/main/pages/3_%F0%9F%86%94_%20%E6%89%B9%E9%87%8F%E9%A2%98%E5%86%99%E5%9F%9F%E5%90%8D%E9%93%AD%E6%96%87.py)
111
+ - 请务必访问 **[ethpen.com](https://ethpen.com)** 官方网站。您可以确保这里的代码无恶意,放心地使用。
112
+ - 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
113
+ - 我们建议您使用备用账号,并避免在账号中存放大额资金。
114
+ - 若您对此代码存有疑虑,建议您利用如 [ChetGPT](https://chat.openai.com/)、[Bard](https://bard.google.com/) 或 [Claude](https://claude.ai/) 等知名 AI 平台进行查询,以判断是否含有恶意代码。
115
+ ''')
116
+
117
+ # 连接的网络 ID。比如说,1 代表主网络,5 代表 Goerli 测试网络,11155111 代表 Sepolia 测试网络,如果你不放心,可以先用测试网试试。
118
+ net_options = {
119
+ '1': 'Mainnet',
120
+ '5': 'Goerli',
121
+ '11155111': 'Sepolia'
122
+ }
123
+ selected_option = st.selectbox(
124
+ '**网络 ID**',
125
+ list(net_options.keys()),
126
+ format_func=lambda x: f"{x} ({net_options[x]})"
127
+ )
128
+ chain_id = int(selected_option)
129
+
130
+ # 这里配置 Ethereum PRC URL,如果你没有,请到 infura.io 或者 alchemy.com 申请一个免费的 API
131
+ token_eth_prc_url = st.text_input(
132
+ f'**Ethereum PRC 链接**:选填,你可以去 [infura.io](https://app.infura.io/) 或者 [alchemy.com](https://alchemy.com/) 免费申请一个',
133
+ f'https://{net_options[str(chain_id)]}.infura.io/v3/eab7f935b9af45e1a54f7d7ed06c5206')
134
+ w3 = Web3(Web3.HTTPProvider(f'{token_eth_prc_url}'))
135
+ # 初始化当前账户索引为 0
136
+ current_account_index = 0
137
+ # 收集和显示所有交易的结果
138
+ transaction_results = []
139
+ # 创建账户列表
140
+ accounts = []
141
+ # 使用字典来跟踪每个地址的nonce
142
+ nonces = {}
143
+
144
+ # 启用多账户操作
145
+ if st.checkbox(f'启用**多账户**操作'):
146
+ # 多账户的文本框
147
+ account_list = st.text_area(f'输入多个 **ETH 地址及其对应的私钥**,用英文逗号分隔(,),如下:地址,私钥')
148
+ if account_list: # 如果账户列表有内容
149
+ for line in account_list.split('\n'): # 根据换行符划分账户
150
+ if ',' in line: # 检查是否包含逗号
151
+ address, key = line.split(',') # 分开地址和私钥
152
+ if is_valid_eth_address(address) and is_valid_eth_private_key(key): # 验证地址和私钥
153
+ current_nonce = w3.eth.get_transaction_count(address) # 获取地址的 nonce
154
+ nonces[address] = current_nonce # 记录地址的 nonce
155
+ accounts.append((address.strip(), key.strip())) # 保存地址和私钥还有 nonce
156
+ else:
157
+ st.error(f"地址 {address} 或私钥 {key} 无效,请检查!")
158
+ st.stop()
159
+ else:
160
+ st.error(f"输入格式错误,请确保每行包含一个地址和一个私钥,并使用英文逗号分隔(,)。错误行:**{line}**")
161
+ st.stop()
162
+ else:
163
+ account_address = st.text_input('填写你的 **ETH 地址**:')
164
+ private_key = st.text_input('填写你的 **ETH 地址对应的私钥**:', type="password")
165
+ if account_address and private_key: # 如果地址和私钥有内容
166
+ if is_valid_eth_address(account_address) and is_valid_eth_private_key(private_key): # 验证地址和私钥
167
+ current_nonce = w3.eth.get_transaction_count(account_address) # 获取地址的 nonce
168
+ nonces[account_address] = current_nonce # 记录地址的 nonce
169
+ accounts.append((account_address.strip(), private_key.strip())) # 保存地址和私钥还有 nonce
170
+ else:
171
+ st.error("地址或私钥无效,请检查!")
172
+ st.stop()
173
+
174
+ # 配置铭文文本
175
+ ethscriptions_str = st.text_area(f'输入**多个域名铭文或其他**,可以用空格、换行符、英文逗号(,)分开,不要带 data:, 前缀,不要带域名后缀')
176
+ name_options = ["自定义", ".eth", ".eths", ".tree", ".honk", ".etch"]
177
+ name_selected_option = st.selectbox(f'选择**域名后缀**', name_options)
178
+ if name_selected_option == '自定义':
179
+ name_selected_option = st.text_input('输入**自定义的域名**:')
180
+ # 以空格、换行符、英文逗号分隔文本并加上后缀
181
+ ethscription_list = split_and_append(ethscriptions_str, name_selected_option)
182
+
183
+ # 判断铭文文本里是否包含空格、换行符,而且所有的字母都必须为小写。
184
+ if not validate_input(''.join(ethscription_list)):
185
+ st.warning("**请注意**:通常代币铭文文本里不能包含空格、换行符,而且所有的字母都必须为小写。")
186
+
187
+ # 题写铭文之前检查该铭文有没有被题写
188
+ if st.checkbox(f'题写铭文之前**检查该铭文有没有被题写**'):
189
+ token_check = True
190
+ else:
191
+ token_check = False
192
+
193
+ # 每次交易成功后暂停 3 秒
194
+ if st.checkbox(f'每次交易完成后暂停 3 秒'):
195
+ sleep_3s = True
196
+ else:
197
+ sleep_3s = False
198
+
199
+ # 点击发送交易开始
200
+ if st.button(f'开始**发送交易**'):
201
+ if not accounts or not ethscriptions_str or not name_selected_option: # 检查是否留空
202
+ st.error(f'请正确谨慎地填写内容,每一项都**不应留空**。')
203
+ st.stop()
204
+ else:
205
+ st.toast('看起来你输入的内容均无没有问题!', icon='🥳')
206
+
207
+ st.toast(f'开始任务,需要题写的铭文总量为:{len(ethscription_list)}', icon='😎')
208
+
209
+ # 对代币铭文 id 进行循环
210
+ for name_str in ethscription_list:
211
+ # 使用当前账户发送交易,获取当前账户的 nonce
212
+ address, key = accounts[current_account_index]
213
+ # 获取 gas
214
+ gas_price = w3.eth.gas_price
215
+ # 得到完整的铭文文本
216
+ if not name_str.startswith('data:,'):
217
+ input_data = f'data:,{name_str}'
218
+
219
+ # 根据是否检查的开关进行
220
+ if token_check:
221
+ # 这里是开了检查后请求 Ethscriptions API
222
+ if check_content_exists(sha256(input_data)):
223
+ # ��回数据为 Ture,说明该铭文已经被题写,打印信息
224
+ st.toast(f'{input_data} 已经被题写!', icon='☹️')
225
+ else:
226
+ # 返回数据为 False,说明该铭文还没被题写,发送交易
227
+ # 使用 current_nonce 发送交易
228
+ data, tx_hash = send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
229
+ # 记录最后输出的结果
230
+ transaction_results.append(f"{address} | {data} | Transaction Hash: {tx_hash}")
231
+ # 交易成功后,手动增加 nonce 值
232
+ nonces[address] += 1
233
+ else:
234
+ # 这里是未开检查后直接发送交易
235
+ # 使用 current_nonce 发送交易
236
+ data, tx_hash = send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
237
+ # 记录最后输出的结果
238
+ transaction_results.append(f"{address} | {data} | Transaction Hash: {tx_hash}")
239
+ # 交易成功后,手动增加 nonce 值
240
+ nonces[address] += 1
241
+ # 更新当前账户索引,确保索引始终在账户列表的范围内
242
+ current_account_index = (current_account_index + 1) % len(accounts)
243
+ # 暂停 3 秒
244
+ if sleep_3s:
245
+ time.sleep(3) # 暂停三秒
246
+ st.toast(f'所有任务已经完成。', icon='🎉')
247
+ # 庆祝动画
248
+ st.balloons()
249
+ # 显示所有交易的结果
250
+ st.code('\n'.join(transaction_results))
pages/3_🪙_ 批量题写代币铭文.py ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ethpen.com
2
+ # 最后更新日期:2023 年 8 月 18 日
3
+
4
+ # 在使用之前,敬请仔细阅读说明,感谢您的配合。
5
+ # 请务必访问 ethpen.com 官方网站。您可以确保这里的代码无恶意,安全地复制。
6
+ # 你只需要拥有一个 HuggingFace.co 账户。
7
+ # 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
8
+ # 我们建议您使用备用账号,并避免在账号中存放大额资金。
9
+ # 若您对此代码存有疑虑,建议您利用如 ChetGPT、Bard 或 Claude 等知名 AI 平台进行查询,以判断是否含有恶意代码。
10
+ # 请查看我们的例子 https://ethscriptions-name.hf.space。
11
+
12
+ # 导入运行代码所需要的库
13
+ import streamlit as st # streamlit app
14
+ from web3 import Web3 # 与以太坊交互的库
15
+ import hashlib # 用于数据哈希
16
+ import requests # 用于发送网络请求
17
+ import re # 用于正则表达式
18
+ import time # 用于时间相关
19
+
20
+
21
+ # 检查 ETH 地址是否有效
22
+ def is_valid_eth_address(address):
23
+ if re.match("^0x[0-9a-fA-F]{40}$", address):
24
+ return True
25
+ return False
26
+
27
+
28
+ # 检查 Ethereum 私钥是否有效
29
+ def is_valid_eth_private_key(private_key):
30
+ if re.match("^[0-9a-fA-F]{64}$", private_key):
31
+ return True
32
+ return False
33
+
34
+
35
+ # 验证输入的铭文文本是否含有空格和换行符,而且字母全部为小写
36
+ def validate_input(data_str):
37
+ if re.search(r'[A-Z\s\n]', data_str): # 查找大写字母、空格或换行符
38
+ return False
39
+ return True
40
+
41
+
42
+ # 把文字转换成 16 进制
43
+ def text_to_hex(text):
44
+ return ''.join(format(ord(char), '02x') for char in text)
45
+
46
+
47
+ # 使用sha256算法计算哈希
48
+ def sha256(input_string):
49
+ sha256 = hashlib.sha256()
50
+ sha256.update(input_string.encode('utf-8'))
51
+ return sha256.hexdigest()
52
+
53
+
54
+ # 使用 Ethscriptions API(主网)检查某个铭文是否已题写
55
+ def check_content_exists(sha):
56
+ # 定义请求的网址
57
+ endpoint = f"/ethscriptions/exists/{sha}"
58
+ response = requests.get('https://mainnet-api.ethscriptions.com/api' + endpoint)
59
+ # 如果返回状态码是200,说明请求成功,然后返回结果(Ture or False)
60
+ if response.status_code == 200:
61
+ return response.json()['result']
62
+
63
+
64
+ # 发送自己到自己 0ETH 的交易
65
+ def send_transaction(w3, account_address, private_key, chain_id, gas_price, input_data, current_nonce):
66
+
67
+ # 设置交易的相关信息
68
+ tx = {
69
+ 'chainId': chain_id, # 网络 ID
70
+ 'gas': 25000, # 如果交易 gas 过低,可适当调高
71
+ 'gasPrice': gas_price, # gas 的价格
72
+ 'nonce': current_nonce,
73
+ 'to': account_address, # 接收地址为自己
74
+ 'value': 0, # 金额为 0ETH
75
+ 'data': text_to_hex(input_data), # 铭文内容
76
+ }
77
+
78
+ # 用私钥签名这个交易
79
+ signed_tx = w3.eth.account.sign_transaction(tx, private_key)
80
+ # 发送签名后的交易并获取交易哈希
81
+ tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
82
+ # 打印结果信息
83
+ st.toast(f'{input_data}', icon='✅')
84
+ # 返回铭文还有交易哈希
85
+ return input_data, tx_hash.hex()
86
+
87
+ # 网页前端显示
88
+ # 网页标题
89
+ st.markdown('# [ethpen.com](https://ethpen.com) 代币铭文批量题写')
90
+ # 提醒
91
+ st.info('''##### 在使用之前,敬请仔细阅读说明,感谢您的配合。
92
+ - 我们的网站已经全部开源,此页面的代码为:[4_🪙_批量题写代币铭文.py](https://huggingface.co/spaces/Ethscriptions/eths/blob/main/pages/4_%F0%9F%AA%99_%20%E6%89%B9%E9%87%8F%E9%A2%98%E5%86%99%E4%BB%A3%E5%B8%81%E9%93%AD%E6%96%87.py)
93
+ - 请务必访问 **[ethpen.com](https://ethpen.com)** 官方网站。您可以确保这里的代码无恶意,放心地使用。
94
+ - 在使用过程中,请根据规定准确填写信息,以确保程序顺畅运行。
95
+ - 我们建议您使用备用账号,并避免在账号中存放大额资金。
96
+ - 若您对此代码存有疑虑,建议您利用如 [ChetGPT](https://chat.openai.com/)、[Bard](https://bard.google.com/) 或 [Claude](https://claude.ai/) 等知名 AI 平台进行查询,以判断是否含有恶意代码。
97
+ ''')
98
+
99
+ # 连接的网络 ID。比如说,1 代表 Mainnet,5 代表 Goerli 测试网络,11155111 代表 Sepolia 测试网络,如果你不放心,可以先用测试网试试。
100
+ net_options = {
101
+ '1': 'Mainnet',
102
+ '5': 'Goerli',
103
+ '11155111': 'Sepolia'
104
+ }
105
+ selected_option = st.selectbox(
106
+ '**网络 ID**',
107
+ list(net_options.keys()),
108
+ format_func=lambda x: f"{x} ({net_options[x]})"
109
+ )
110
+ chain_id = int(selected_option)
111
+
112
+ # 这里配置 Ethereum PRC URL,如果你没有,请到 infura.io 或者 alchemy.com 申请一个免费的 API
113
+ token_eth_prc_url = st.text_input(
114
+ f'**Ethereum PRC 链接**:选填,你可以去 [infura.io](https://app.infura.io/) 或者 [alchemy.com](https://alchemy.com/) 免费申请一个',
115
+ f'https://{net_options[str(chain_id)]}.infura.io/v3/eab7f935b9af45e1a54f7d7ed06c5206')
116
+ w3 = Web3(Web3.HTTPProvider(f'{token_eth_prc_url}'))
117
+
118
+ # 初始化当前账户索引为 0
119
+ current_account_index = 0
120
+ # 收集和显示所有交易的结果
121
+ transaction_results = []
122
+ # 创建账户列表
123
+ accounts = []
124
+ # 使用字典来跟踪每个地址的nonce
125
+ nonces = {}
126
+
127
+ # 启用多账户操作
128
+ if st.checkbox(f'启用**多账户**操作'):
129
+ # 多账户的文本框
130
+ account_list = st.text_area(f'输入多个 **ETH 地址及其对应的私钥**,用英文逗号分隔(,),如下:地址,私钥')
131
+ if account_list: # 如果账户列表有内容
132
+ for line in account_list.split('\n'): # 根据换行符划分账户
133
+ if ',' in line: # 检查是否包含逗号
134
+ address, key = line.split(',') # 分开地址和私钥
135
+ if is_valid_eth_address(address) and is_valid_eth_private_key(key): # 验证地址和私钥
136
+ current_nonce = w3.eth.get_transaction_count(address) # 获取地址的 nonce
137
+ nonces[address] = current_nonce # 记录地址的 nonce
138
+ accounts.append((address.strip(), key.strip())) # 保存地址和私钥还有 nonce
139
+ else:
140
+ st.error(f"地址 {address} 或私钥 {key} 无效,请检查!")
141
+ st.stop()
142
+ else:
143
+ st.error(f"输入格式错误,请确保每行包含一个地址和一个私钥,并使用英文逗号分隔(,)。错误行:**{line}**")
144
+ st.stop()
145
+ else:
146
+ account_address = st.text_input('填写你的 **ETH 地址**:')
147
+ private_key = st.text_input('填写你的 **ETH 地址对应的私钥**:', type="password")
148
+ if account_address and private_key: # 如果地址和私钥有内容
149
+ if is_valid_eth_address(account_address) and is_valid_eth_private_key(private_key): # 验证地址和私钥
150
+ current_nonce = w3.eth.get_transaction_count(account_address) # 获取地址的 nonce
151
+ nonces[account_address] = current_nonce # 记录地址的 nonce
152
+ accounts.append((account_address.strip(), private_key.strip())) # 保存地址和私钥还有 nonce
153
+ else:
154
+ st.error("地址或私钥无效,请检查!")
155
+ st.stop()
156
+
157
+ # 配置铭文文本
158
+ token_protocol = st.text_input('填写需要题写代币铭文协议 **Protocol(p)**:', 'erc-20')
159
+ token_operation = st.text_input('填写需要题写代币铭文操作 **Operation(op)**:', 'mint')
160
+ token_ticker = st.text_input('填写需要题写代币铭文简称 **Ticker(tick)**:')
161
+ token_min_id = st.number_input('填写需要题写代币铭文范围的**最小 ID(id)**:', min_value=1, value=1, step=1)
162
+ token_max_id = st.number_input('填写需要题写代币铭文范围的**最大 ID(id)**:', value=21000, step=1)
163
+ token_amount = st.number_input('填写需要题写代币铭文数量 **Amount(amt)**:', min_value=1, value=1000, step=1)
164
+ st.markdown('###### 预览你需要题写的代币铭文:')
165
+ st.code(
166
+ f'data:,{{"p":"{token_protocol}","op":"{token_operation}","tick":"{token_ticker}","id":"{token_min_id}","amt":"{token_amount}"}}',
167
+ language="json", line_numbers=False)
168
+ # 判断铭文文本里是否包含空格、换行符,而且所有的字母都必须为小写。
169
+ if not validate_input(
170
+ f'data:,{{"p":"{token_protocol}","op":"{token_operation}","tick":"{token_ticker}","id":"{token_min_id}","amt":"{token_amount}"}}'):
171
+ st.warning("**请注意**:通常代币铭文文本里不能包含空格、换行符,而且所有的字母都必须为小写。")
172
+
173
+ # 题写铭文之前检查该铭文有没有被题写
174
+ if st.checkbox(f'题写铭文之前**检查该铭文有没有被题写**'):
175
+ token_check = True
176
+ else:
177
+ token_check = False
178
+
179
+ # 每次交易成功后暂停 3 秒
180
+ if st.checkbox(f'每次交易完成后暂停 3 秒'):
181
+ sleep_3s = True
182
+ else:
183
+ sleep_3s = False
184
+
185
+ # 点击发送交易开始
186
+ if st.button(f'开始**发送交易**'):
187
+ if not accounts or not token_protocol or not token_operation or not token_ticker: # 检查是否留空
188
+ st.error(f'请正确谨慎地填写内容,每一项都**不应留空**。')
189
+ st.stop()
190
+ else:
191
+ st.toast('看起来你输入的内容均无没有问题!', icon='🥳')
192
+
193
+ st.toast(f'开始任务,需要题写的铭文总量为:{token_max_id - token_min_id + 1}', icon='😎')
194
+
195
+ # 对代币铭文 id 进行循环
196
+ for the_id in range(token_min_id, token_max_id + 1):
197
+ # 使用当前账户发送交易,获取当前账户的 nonce
198
+ address, key = accounts[current_account_index]
199
+ # 得到完整的铭文文本
200
+ input_data = f'data:,{{"p":"{token_protocol}","op":"{token_operation}","tick":"{token_ticker}","id":"{the_id}","amt":"{token_amount}"}}'
201
+ # 获取 gas
202
+ gas_price = w3.eth.gas_price
203
+ # 根据是否检查的开关进行
204
+ if token_check:
205
+ # 这里是开了检查后请求 Ethscriptions API
206
+ if check_content_exists(sha256(input_data)):
207
+ # 返回数���为 Ture,说明该铭文已经被题写,打印信息
208
+ st.toast(f'{input_data} 已经被题写!', icon='☹️')
209
+ else:
210
+ # 返回数据为 False,说明该铭文还没被题写,发送交易
211
+ # 使用 current_nonce 发送交易
212
+ data, tx_hash = send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
213
+ # 记录最后输出的结果
214
+ transaction_results.append(f"{address} | {data} | Transaction Hash: {tx_hash}")
215
+ # 交易成功后,手动增加 nonce 值
216
+ nonces[address] += 1
217
+ else:
218
+ # 这里是未开检查后直接发送交易
219
+ # 使用 current_nonce 发送交易
220
+ data, tx_hash = send_transaction(w3, address, key, chain_id, gas_price, input_data, nonces[address])
221
+ # 记录最后输出的结果
222
+ transaction_results.append(f"{address} | {data} | Transaction Hash: {tx_hash}")
223
+ # 交易成功后,手动增加 nonce 值
224
+ nonces[address] += 1
225
+ # 更新当前账户索引,确保索引始终在账户列表的范围内
226
+ current_account_index = (current_account_index + 1) % len(accounts)
227
+ # 暂停 3 秒
228
+ if sleep_3s:
229
+ time.sleep(3) # 暂停三秒
230
+ st.toast(f'所有任务已经完成。', icon='🎉')
231
+ # 庆祝动画
232
+ st.balloons()
233
+ # 显示所有交易的结果
234
+ st.code('\n'.join(transaction_results))
pages/4_🕵️‍♀️_Ethscriptions Data.py ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import os
4
+ from web3 import Web3
5
+ import sqlite3
6
+ import time
7
+ from datetime import datetime, timezone
8
+ import threading
9
+ import base64
10
+
11
+ test1 = '233'
12
+ # 使用你的Ethereum节点的RPC地址
13
+ w3 = Web3(Web3.HTTPProvider("https://mainnet.infura.io/v3/9bbc614b8a1d49d59869e97d0ee3bf61"))
14
+
15
+ # 获取当前文件目录
16
+ current_dir = os.path.dirname(__file__)
17
+ parent_dir = os.path.dirname(current_dir)
18
+ # 构造数据库文件路径
19
+ eths_db_file = os.path.join(parent_dir, 'data', 'eths_data.db')
20
+ ethscrptions_db_file = os.path.join(parent_dir, 'data', 'ethscriptions_data.db')
21
+
22
+ ethscriptions_con = sqlite3.connect(ethscrptions_db_file)
23
+ ethscriptions_cur = ethscriptions_con.cursor()
24
+
25
+ def get_eths_data():
26
+ # Initialize connection to SQLite database
27
+ eths_conn = sqlite3.connect(eths_db_file)
28
+ eths_cur = eths_conn.cursor()
29
+ # Create table to store ETHS data
30
+ eths_cur.execute('''
31
+ CREATE TABLE IF NOT EXISTS eths_data
32
+ (date text,
33
+ eth_price real,
34
+ eths_price real,
35
+ eths_market_cap integer,
36
+ eths_owners integer,
37
+ eths_volume24h real,
38
+ eths_totalLocked integer,
39
+ eths_stakers integer,
40
+ eths_tvl real)
41
+ ''')
42
+ while True:
43
+ try:
44
+ # Get ETHS price data
45
+ price_url = 'https://www.etch.market/api/markets/collections/details'
46
+ price_params = {'category': 'token', 'collectionName': 'erc-20 eths'}
47
+ price_response = requests.get(price_url, params=price_params)
48
+ # Get ETHS staking data
49
+ staking_url = 'https://www.etch.market/api/staking/statistics/erc-20%20eths'
50
+ staking_response = requests.get(staking_url)
51
+ if price_response.status_code == 200 and staking_response.status_code == 200:
52
+ price_response = price_response.json()
53
+ staking_response = staking_response.json()
54
+ if price_response['message'] == 'success' and staking_response['message'] == 'success':
55
+ price_data = price_response['data']['collections']
56
+ staking_data = staking_response['data']
57
+ # Extract values from API responses
58
+ eth_price = float(price_data['unitPriceUsd']) / float(price_data['unitPrice'])
59
+ eths_price = float(price_data['unitPriceUsd'])
60
+ eths_market_cap = eths_price * 21000000
61
+ eths_owners = int(price_data['owners'])
62
+ eths_volume24h = float(price_data['volume24h']) * eth_price
63
+ eths_totalLocked = int(staking_data['totalLocked']) * 2
64
+ eths_stakers = int(staking_data['stakers'])
65
+ eths_tvl = float(staking_data['tvl']) * eth_price
66
+ # Current date/time
67
+ now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
68
+ # Package data into tuple
69
+ data = (now, eth_price, eths_price, eths_market_cap, eths_owners, eths_volume24h,
70
+ eths_totalLocked, eths_stakers, eths_tvl)
71
+ eths_cur.execute('DELETE FROM eths_data')
72
+ eths_cur.execute('INSERT INTO eths_data VALUES (?,?,?,?,?,?,?,?,?)', data)
73
+ eths_conn.commit()
74
+ except Exception as e:
75
+ pass
76
+ time.sleep(60)
77
+
78
+
79
+ def get_ethscriptions_data():
80
+ global ethscrptions_db_file
81
+ # 创建表
82
+ ethscriptions_thread_con = sqlite3.connect(ethscrptions_db_file)
83
+ ethscriptions_thread_cur = ethscriptions_thread_con.cursor()
84
+ ethscriptions_thread_cur.execute('''CREATE TABLE IF NOT EXISTS data
85
+ (block_time text, block_number integer, data text, owner text, hash text)''')
86
+
87
+ ethscriptions_thread_cur.execute('''CREATE TABLE IF NOT EXISTS process_blocks
88
+ (block_number integer)''')
89
+
90
+ # 获取最新的区块
91
+ latest_block_number_thread = w3.eth.block_number
92
+ ethscriptions_thread_cur.execute("SELECT MAX(block_number) FROM process_blocks")
93
+ result_thread = ethscriptions_thread_cur.fetchone()
94
+ start_block_thread = result_thread[0] - 10
95
+ while True:
96
+
97
+ for block_number in range(start_block_thread, latest_block_number_thread):
98
+
99
+ block = w3.eth.get_block(block_number, full_transactions=True)
100
+
101
+ # 获取该区块中所有交易的列表
102
+ transactions = block['transactions']
103
+ for tx in transactions:
104
+ print(tx['input'])
105
+ print(type(tx['input']))
106
+ input_data = tx['input']
107
+
108
+ if input_data.startswith(r"0x646174613a2c"):
109
+ # if bytes.fromhex(input_data).startswith(b"data:,"):
110
+
111
+ existing_data = ethscriptions_thread_cur.execute("SELECT * FROM data WHERE data=?",
112
+ (input_data,)).fetchone()
113
+
114
+ if not existing_data:
115
+ timestamp = datetime.fromtimestamp(block['timestamp'], tz=timezone.utc)
116
+
117
+ ethscriptions_thread_cur.execute('''INSERT INTO data (block_time, block_number, data, owner, hash)
118
+ VALUES (?, ?, ?, ?, ?)''',
119
+ (
120
+ timestamp, tx['blockNumber'], input_data, tx['to'],
121
+ tx['hash'].hex()))
122
+
123
+ ethscriptions_thread_con.commit()
124
+ print(f'-----{input_data}-----')
125
+
126
+ # 更新process_blocks表
127
+ ethscriptions_thread_cur.execute("INSERT INTO process_blocks (block_number) VALUES (?)",
128
+ (block_number,))
129
+ # 只保留最新的一条记录
130
+ ethscriptions_thread_cur.execute("DELETE FROM process_blocks WHERE block_number != ?",
131
+ (block_number,))
132
+ ethscriptions_thread_con.commit()
133
+
134
+ print(block_number)
135
+
136
+ # 获取下次开始的区块号
137
+ ethscriptions_thread_cur.execute("SELECT block_number FROM process_blocks")
138
+ result_thread = ethscriptions_thread_cur.fetchone()
139
+ start_block_thread = result_thread[0] - 1
140
+
141
+ # 获取最新的区块
142
+ latest_block_number_thread = w3.eth.block_number
143
+
144
+ # 等待1分钟
145
+ time.sleep(60)
146
+
147
+
148
+ # Streamlit app layout
149
+ st.set_page_config(page_title="EthPen - 批量查询铭文状态", page_icon="🔢", layout='wide', initial_sidebar_state='auto')
150
+
151
+ st.error('功能开发中,仅供参考!')
152
+ st.title(f'EthPen - Ethscriptions 数据总揽')
153
+ st.markdown(f'## eths 数据总揽')
154
+ eths_conn = sqlite3.connect(eths_db_file)
155
+ eths_cur = eths_conn.cursor()
156
+ # 查询eths_data表中所有数据
157
+ eths_cur.execute('SELECT * FROM eths_data')
158
+ # 获取所有结果
159
+ eths_data = eths_cur.fetchall()
160
+ if eths_data:
161
+ col1, col2 = st.columns(2)
162
+ with col1:
163
+ eths_price = st.metric(label='ETHS 价格', value=f'${eths_data[0][2]:,.2f}')
164
+
165
+ eths_price = st.metric(label='总量', value='21,000,000')
166
+
167
+ eths_owners = st.metric(label='持有人数', value=f'{eths_data[0][4]:,.0f}')
168
+
169
+ eths_stakers = st.metric(label='质押人数', value=f'{eths_data[0][7]:,.0f}')
170
+ with col2:
171
+ eths_tvl = st.metric(label='总市值', value=f'${eths_data[0][3]:,.0f}')
172
+
173
+ eths_volume24h = st.metric(label='24小时成交量', value=f'${eths_data[0][5]:,.0f}')
174
+
175
+ eths_totalLocked = st.metric(label='质押总量', value=f'{eths_data[0][6]:,.0f} $eths')
176
+
177
+ eths_stakers = st.metric(label='ETHS TVL', value=f'${eths_data[0][8]:,.0f}')
178
+
179
+
180
+ ethscriptions_cur.execute("SELECT block_number FROM process_blocks")
181
+ result = ethscriptions_cur.fetchone()
182
+ processed_block = result[0]
183
+ latest_block_number = w3.eth.block_number
184
+ st.markdown(f'EthPen Ethscriptions Index Status:当前 Ethereum 最高区块:{latest_block_number},已处理区块:{processed_block}')
185
+
186
+ download = st.checkbox('⏬️', value=False)
187
+ if download:
188
+ current_dir = os.path.dirname(__file__)
189
+ parent_dir = os.path.dirname(current_dir)
190
+ # Constructing database file path
191
+ ethscrptions_db_file = os.path.join(parent_dir, 'data', 'ethscriptions_data.db')
192
+ st.download_button(
193
+ label='下载数据库',
194
+ data=open(ethscrptions_db_file,'rb'),
195
+ file_name='ethscriptions_data.db',
196
+ mime='application/octet-stream'
197
+ )
198
+ # 修改状态值
199
+ old_state = "0"
200
+ ethscriptions_cur.execute("UPDATE thread_start_state SET state = ?", (old_state,))
201
+ ethscriptions_con.commit()
202
+
203
+ while True:
204
+ time.sleep(10)
205
+ # 查询state列的值
206
+ ethscriptions_cur.execute("SELECT state FROM thread_start_state")
207
+ state_value = ethscriptions_cur.fetchone()[0]
208
+ if state_value == "0":
209
+ # 修改状态值
210
+ new_state = "1"
211
+ ethscriptions_cur.execute("UPDATE thread_start_state SET state = ?", (new_state,))
212
+ ethscriptions_con.commit()
213
+
214
+ eths_thread = threading.Thread(target=get_eths_data)
215
+ ethscriptions_thread = threading.Thread(target=get_ethscriptions_data)
216
+
217
+ # 启动线程
218
+ eths_thread.start()
219
+ ethscriptions_thread.start()
220
+
221
+ # 等待线程结束
222
+ eths_thread.join()
223
+ ethscriptions_thread.join()
requirements.txt ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==23.1.0
2
+ aiohttp==3.8.5
3
+ aiosignal==1.3.1
4
+ altair==5.0.1
5
+ annotated-types==0.5.0
6
+ anyio==3.7.1
7
+ async-timeout==4.0.2
8
+ attrs==23.1.0
9
+ bitarray==2.8.0
10
+ blinker==1.6.2
11
+ cachetools==5.3.1
12
+ certifi==2023.5.7
13
+ charset-normalizer==3.1.0
14
+ click==8.1.6
15
+ contourpy==1.1.0
16
+ cycler==0.11.0
17
+ cytoolz==0.12.2
18
+ decorator==5.1.1
19
+ docopt==0.6.2
20
+ eth-abi==4.1.0
21
+ eth-account==0.9.0
22
+ eth-hash==0.5.2
23
+ eth-keyfile==0.6.1
24
+ eth-keys==0.4.0
25
+ eth-rlp==0.3.0
26
+ eth-typing==3.4.0
27
+ eth-utils==2.2.0
28
+ exceptiongroup==1.1.2
29
+ fastapi==0.100.1
30
+ ffmpy==0.3.1
31
+ filelock==3.12.2
32
+ fonttools==4.42.0
33
+ frozenlist==1.4.0
34
+ fsspec==2023.6.0
35
+ gitdb==4.0.10
36
+ GitPython==3.1.32
37
+ gradio==3.39.0
38
+ gradio_client==0.3.0
39
+ h11==0.14.0
40
+ hexbytes==0.3.1
41
+ httpcore==0.17.3
42
+ httpx==0.24.1
43
+ huggingface-hub==0.16.4
44
+ idna==3.4
45
+ importlib-metadata==6.8.0
46
+ importlib-resources==6.0.0
47
+ Jinja2==3.1.2
48
+ jsonschema==4.18.4
49
+ jsonschema-specifications==2023.7.1
50
+ kiwisolver==1.4.4
51
+ linkify-it-py==2.0.2
52
+ lru-dict==1.2.0
53
+ markdown-it-py==2.2.0
54
+ MarkupSafe==2.1.3
55
+ matplotlib==3.7.2
56
+ mdit-py-plugins==0.3.3
57
+ mdurl==0.1.2
58
+ multidict==6.0.4
59
+ numpy==1.25.1
60
+ orjson==3.9.2
61
+ packaging==23.1
62
+ pandas==2.0.3
63
+ parsimonious==0.9.0
64
+ Pillow==9.5.0
65
+ pipreqs==0.4.13
66
+ protobuf==4.23.4
67
+ pyarrow==12.0.1
68
+ pycryptodome==3.18.0
69
+ pydantic==2.1.1
70
+ pydantic_core==2.4.0
71
+ pydeck==0.8.0
72
+ pydub==0.25.1
73
+ Pygments==2.15.1
74
+ Pympler==1.0.1
75
+ pyparsing==3.0.9
76
+ python-dateutil==2.8.2
77
+ python-multipart==0.0.6
78
+ pytz==2023.3
79
+ pytz-deprecation-shim==0.1.0.post0
80
+ pyunormalize==15.0.0
81
+ PyYAML==6.0.1
82
+ referencing==0.30.0
83
+ regex==2023.6.3
84
+ requests==2.31.0
85
+ rich==13.4.2
86
+ rlp==3.0.0
87
+ rpds-py==0.9.2
88
+ schedule==1.2.0
89
+ semantic-version==2.10.0
90
+ six==1.16.0
91
+ smmap==5.0.0
92
+ sniffio==1.3.0
93
+ starlette==0.27.0
94
+ streamlit==1.26.0
95
+ tenacity==8.2.2
96
+ toml==0.10.2
97
+ toolz==0.12.0
98
+ tornado==6.3.2
99
+ tqdm==4.65.0
100
+ typing_extensions==4.7.1
101
+ tzdata==2023.3
102
+ tzlocal==4.3.1
103
+ uc-micro-py==1.0.2
104
+ urllib3==2.0.3
105
+ uvicorn==0.23.2
106
+ validators==0.20.0
107
+ web3==6.6.1
108
+ websockets==11.0.3
109
+ yarg==0.1.9
110
+ yarl==1.9.2
111
+ zipp==3.16.2