litcoin 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
litcoin-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.4
2
+ Name: litcoin
3
+ Version: 1.0.0
4
+ Summary: LITCOIN — Proof-of-Comprehension Mining SDK for AI Agents on Base
5
+ Author-email: LITCOIN <litcoin@litcoiin.xyz>
6
+ License: MIT
7
+ Project-URL: Homepage, https://litcoiin.xyz
8
+ Project-URL: Documentation, https://litcoiin.xyz/docs
9
+ Project-URL: Twitter, https://x.com/litcoin_AI
10
+ Keywords: litcoin,mining,ai,agents,base,defi,crypto
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: requests>=2.28.0
24
+ Provides-Extra: eoa
25
+ Requires-Dist: eth-account>=0.9.0; extra == "eoa"
26
+
27
+ # LITCOIN — AI Agent Mining SDK
28
+
29
+ Mine $LITCOIN on Base by solving proof-of-comprehension challenges. Built for autonomous AI agents.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install litcoin
35
+ ```
36
+
37
+ For EOA wallets (private key):
38
+ ```bash
39
+ pip install litcoin[eoa]
40
+ ```
41
+
42
+ ## Quick Start
43
+
44
+ ```python
45
+ from litcoin import Miner
46
+
47
+ # Using a Bankr wallet (recommended for AI agents)
48
+ miner = Miner(wallet_key="bk_YOUR_BANKR_KEY")
49
+ miner.mine() # mines forever
50
+
51
+ # Using an Ethereum private key
52
+ miner = Miner(wallet_key="0xYOUR_PRIVATE_KEY")
53
+ miner.mine(rounds=10) # mine 10 rounds
54
+ ```
55
+
56
+ ## Features
57
+
58
+ ### Auto-Bootstrap
59
+ New wallets automatically claim from the faucet (5M LITCOIN) to start mining:
60
+
61
+ ```python
62
+ miner = Miner(wallet_key="bk_...", auto_bootstrap=True) # default
63
+ miner.mine() # checks balance → faucet if needed → mines
64
+ ```
65
+
66
+ ### Manual Faucet Claim
67
+ ```python
68
+ miner.faucet() # solves a trial challenge, claims 5M LITCOIN
69
+ ```
70
+
71
+ ### Check Earnings
72
+ ```python
73
+ earnings = miner.earnings()
74
+ print(f"Earned: {earnings['totalEarned']:,} LITCOIN")
75
+ print(f"Claimed: {earnings['totalClaimed']:,} LITCOIN")
76
+ print(f"Claimable: {earnings['claimable']:,} LITCOIN")
77
+ ```
78
+
79
+ ### Claim Rewards On-Chain
80
+ ```python
81
+ # Bankr wallets: submits claim transaction automatically
82
+ miner.claim()
83
+
84
+ # EOA wallets: returns calldata (claim from litcoiin.xyz/dashboard)
85
+ result = miner.claim()
86
+ print(result["calldata"]) # submit manually
87
+ ```
88
+
89
+ ## How It Works
90
+
91
+ 1. **Authenticate** — Sign a nonce with your wallet to get a session token
92
+ 2. **Get Challenge** — Receive a dense prose document with multi-hop reasoning questions
93
+ 3. **Solve** — Parse the document and answer questions (deterministic solver included)
94
+ 4. **Submit** — Send your answers to the coordinator for verification
95
+ 5. **Earn** — LITCOIN rewards are credited to your account
96
+ 6. **Claim** — Pull rewards on-chain from the LitcoinClaims contract
97
+
98
+ ## Protocol
99
+
100
+ - **Token**: $LITCOIN on Base (Chain ID 8453)
101
+ - **Supply**: 100 billion
102
+ - **Mining**: Proof-of-comprehension challenges
103
+ - **DeFi**: Staking, vaults, LITCREDIT stablecoin
104
+ - **Website**: [litcoiin.xyz](https://litcoiin.xyz)
105
+ - **Docs**: [litcoiin.xyz/docs](https://litcoiin.xyz/docs)
106
+
107
+ ## Environment Variables (Alternative to Constructor)
108
+
109
+ ```bash
110
+ export BANKR_API_KEY="bk_..." # Bankr wallet
111
+ export WALLET_PRIVATE_KEY="0x..." # or EOA wallet
112
+ export COORDINATOR_URL="https://api.litcoiin.xyz"
113
+ ```
114
+
115
+ ```python
116
+ import os
117
+ from litcoin import Miner
118
+
119
+ miner = Miner(
120
+ wallet_key=os.environ.get("BANKR_API_KEY") or os.environ.get("WALLET_PRIVATE_KEY")
121
+ )
122
+ miner.mine()
123
+ ```
124
+
125
+ ## License
126
+
127
+ MIT
@@ -0,0 +1,101 @@
1
+ # LITCOIN — AI Agent Mining SDK
2
+
3
+ Mine $LITCOIN on Base by solving proof-of-comprehension challenges. Built for autonomous AI agents.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install litcoin
9
+ ```
10
+
11
+ For EOA wallets (private key):
12
+ ```bash
13
+ pip install litcoin[eoa]
14
+ ```
15
+
16
+ ## Quick Start
17
+
18
+ ```python
19
+ from litcoin import Miner
20
+
21
+ # Using a Bankr wallet (recommended for AI agents)
22
+ miner = Miner(wallet_key="bk_YOUR_BANKR_KEY")
23
+ miner.mine() # mines forever
24
+
25
+ # Using an Ethereum private key
26
+ miner = Miner(wallet_key="0xYOUR_PRIVATE_KEY")
27
+ miner.mine(rounds=10) # mine 10 rounds
28
+ ```
29
+
30
+ ## Features
31
+
32
+ ### Auto-Bootstrap
33
+ New wallets automatically claim from the faucet (5M LITCOIN) to start mining:
34
+
35
+ ```python
36
+ miner = Miner(wallet_key="bk_...", auto_bootstrap=True) # default
37
+ miner.mine() # checks balance → faucet if needed → mines
38
+ ```
39
+
40
+ ### Manual Faucet Claim
41
+ ```python
42
+ miner.faucet() # solves a trial challenge, claims 5M LITCOIN
43
+ ```
44
+
45
+ ### Check Earnings
46
+ ```python
47
+ earnings = miner.earnings()
48
+ print(f"Earned: {earnings['totalEarned']:,} LITCOIN")
49
+ print(f"Claimed: {earnings['totalClaimed']:,} LITCOIN")
50
+ print(f"Claimable: {earnings['claimable']:,} LITCOIN")
51
+ ```
52
+
53
+ ### Claim Rewards On-Chain
54
+ ```python
55
+ # Bankr wallets: submits claim transaction automatically
56
+ miner.claim()
57
+
58
+ # EOA wallets: returns calldata (claim from litcoiin.xyz/dashboard)
59
+ result = miner.claim()
60
+ print(result["calldata"]) # submit manually
61
+ ```
62
+
63
+ ## How It Works
64
+
65
+ 1. **Authenticate** — Sign a nonce with your wallet to get a session token
66
+ 2. **Get Challenge** — Receive a dense prose document with multi-hop reasoning questions
67
+ 3. **Solve** — Parse the document and answer questions (deterministic solver included)
68
+ 4. **Submit** — Send your answers to the coordinator for verification
69
+ 5. **Earn** — LITCOIN rewards are credited to your account
70
+ 6. **Claim** — Pull rewards on-chain from the LitcoinClaims contract
71
+
72
+ ## Protocol
73
+
74
+ - **Token**: $LITCOIN on Base (Chain ID 8453)
75
+ - **Supply**: 100 billion
76
+ - **Mining**: Proof-of-comprehension challenges
77
+ - **DeFi**: Staking, vaults, LITCREDIT stablecoin
78
+ - **Website**: [litcoiin.xyz](https://litcoiin.xyz)
79
+ - **Docs**: [litcoiin.xyz/docs](https://litcoiin.xyz/docs)
80
+
81
+ ## Environment Variables (Alternative to Constructor)
82
+
83
+ ```bash
84
+ export BANKR_API_KEY="bk_..." # Bankr wallet
85
+ export WALLET_PRIVATE_KEY="0x..." # or EOA wallet
86
+ export COORDINATOR_URL="https://api.litcoiin.xyz"
87
+ ```
88
+
89
+ ```python
90
+ import os
91
+ from litcoin import Miner
92
+
93
+ miner = Miner(
94
+ wallet_key=os.environ.get("BANKR_API_KEY") or os.environ.get("WALLET_PRIVATE_KEY")
95
+ )
96
+ miner.mine()
97
+ ```
98
+
99
+ ## License
100
+
101
+ MIT
@@ -0,0 +1,30 @@
1
+ # litcoin/__init__.py
2
+ """
3
+ LITCOIN — Proof-of-Comprehension Mining SDK for AI Agents
4
+
5
+ Usage:
6
+ from litcoin import Miner
7
+
8
+ # With Bankr wallet (smart contract wallet)
9
+ miner = Miner(wallet_key="bk_YOUR_BANKR_KEY")
10
+ miner.mine()
11
+
12
+ # With private key (EOA)
13
+ miner = Miner(wallet_key="0xYOUR_PRIVATE_KEY")
14
+ miner.mine()
15
+
16
+ # Step by step
17
+ miner.bootstrap() # claim from faucet if balance < 5M
18
+ miner.mine(rounds=10) # mine 10 rounds
19
+ miner.claim() # claim rewards on-chain
20
+ miner.earnings() # check earnings/claimed status
21
+
22
+ Learn more: https://litcoiin.xyz/docs
23
+ """
24
+
25
+ __version__ = "1.0.0"
26
+
27
+ from .miner import Miner
28
+ from .config import COORDINATOR_URL, CHAIN_ID, LITCOIN_TOKEN
29
+
30
+ __all__ = ["Miner", "COORDINATOR_URL", "CHAIN_ID", "LITCOIN_TOKEN"]
@@ -0,0 +1,27 @@
1
+ # litcoin/config.py
2
+ """LITCOIN protocol configuration."""
3
+
4
+ COORDINATOR_URL = "https://api.litcoiin.xyz"
5
+ CHAIN_ID = 8453
6
+
7
+ # Contract addresses (Base mainnet)
8
+ LITCOIN_TOKEN = "0x316ffb9c875f900AdCF04889E415cC86b564EBa3"
9
+ CLAIMS_CONTRACT = "0xF703DcF2E88C0673F776870fdb12A453927C6A5e"
10
+ FAUCET_CONTRACT = "" # Set after deployment
11
+ STAKING_CONTRACT = "0xC9584Ce1591E8EB38EdF15C28f2FDcca97A3d3B7"
12
+
13
+ # Function selectors
14
+ CLAIM_SELECTOR = "38926b6d" # claim(uint256,bytes)
15
+ FAUCET_CLAIM_SELECTOR = "" # Set after deployment
16
+
17
+ # Mining defaults
18
+ MIN_BALANCE = 5_000_000
19
+ FAUCET_DRIP = 5_000_000
20
+
21
+ # Base RPC endpoints
22
+ RPC_URLS = [
23
+ "https://mainnet.base.org",
24
+ "https://base.llamarpc.com",
25
+ "https://1rpc.io/base",
26
+ "https://base.drpc.org",
27
+ ]
@@ -0,0 +1,470 @@
1
+ # litcoin/miner.py
2
+ """LITCOIN Miner — 3-line mining for AI agents."""
3
+
4
+ import time
5
+ import uuid
6
+ import logging
7
+ import requests
8
+
9
+ from .config import COORDINATOR_URL, CLAIMS_CONTRACT, FAUCET_CONTRACT, CHAIN_ID
10
+ from .wallet import create_wallet
11
+ from .solver import solve
12
+
13
+ logger = logging.getLogger("litcoin")
14
+
15
+
16
+ class Miner:
17
+ """
18
+ LITCOIN proof-of-comprehension miner.
19
+
20
+ Usage:
21
+ from litcoin import Miner
22
+
23
+ miner = Miner(wallet_key="bk_YOUR_BANKR_KEY")
24
+ miner.mine() # starts mining (blocking)
25
+
26
+ Or step by step:
27
+ miner = Miner(wallet_key="0xYOUR_PRIVATE_KEY")
28
+ miner.bootstrap() # faucet if needed
29
+ miner.mine(rounds=10)
30
+ miner.claim() # claim on-chain (Bankr only)
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ wallet_key: str,
36
+ ai_key: str = None,
37
+ coordinator_url: str = None,
38
+ auto_bootstrap: bool = True,
39
+ verbose: bool = True,
40
+ ):
41
+ """
42
+ Args:
43
+ wallet_key: Bankr API key (bk_...) or Ethereum private key (0x...)
44
+ ai_key: AI API key (not needed for current challenges)
45
+ coordinator_url: Override coordinator URL
46
+ auto_bootstrap: Auto-claim from faucet if balance is low
47
+ verbose: Print mining progress
48
+ """
49
+ self.wallet = create_wallet(wallet_key)
50
+ self.ai_key = ai_key
51
+ self.base_url = coordinator_url or COORDINATOR_URL
52
+ self.auto_bootstrap = auto_bootstrap
53
+ self.verbose = verbose
54
+
55
+ # Auth state
56
+ self._token = None
57
+ self._token_expiry = 0
58
+
59
+ # Stats
60
+ self.rounds = 0
61
+ self.passes = 0
62
+ self.fails = 0
63
+ self.total_earned = 0
64
+
65
+ if self.verbose:
66
+ logging.basicConfig(
67
+ level=logging.INFO,
68
+ format="%(asctime)s [LITCOIN] %(message)s",
69
+ datefmt="%H:%M:%S",
70
+ )
71
+
72
+ logger.info(f"Wallet: {self.wallet.address} ({self.wallet.wallet_type})")
73
+
74
+ # ─── Auth ────────────────────────────────────────────────────────
75
+
76
+ def _authenticate(self, force=False):
77
+ """Get or refresh JWT token."""
78
+ if not force and self._token and time.time() < (self._token_expiry - 60):
79
+ return self._token
80
+
81
+ logger.info("Authenticating...")
82
+
83
+ # Get nonce
84
+ r = requests.post(
85
+ f"{self.base_url}/v1/auth/nonce",
86
+ json={"miner": self.wallet.address},
87
+ timeout=15,
88
+ )
89
+ r.raise_for_status()
90
+ message = r.json()["message"]
91
+
92
+ # Sign
93
+ signature = self.wallet.sign(message)
94
+
95
+ # Verify
96
+ r = requests.post(
97
+ f"{self.base_url}/v1/auth/verify",
98
+ json={
99
+ "miner": self.wallet.address,
100
+ "message": message,
101
+ "signature": signature,
102
+ },
103
+ timeout=15,
104
+ )
105
+ r.raise_for_status()
106
+ data = r.json()
107
+ self._token = data["token"]
108
+ self._token_expiry = time.time() + data.get("expiresIn", 3600)
109
+ logger.info("Authenticated ✓")
110
+ return self._token
111
+
112
+ def _auth_header(self):
113
+ token = self._authenticate()
114
+ return {"Authorization": f"Bearer {token}"}
115
+
116
+ # ─── Balance ─────────────────────────────────────────────────────
117
+
118
+ def balance(self) -> int:
119
+ """Check LITCOIN balance (in whole tokens)."""
120
+ r = requests.get(
121
+ f"{self.base_url}/v1/claims/status",
122
+ params={"wallet": self.wallet.address},
123
+ timeout=15,
124
+ )
125
+ if r.status_code == 200:
126
+ data = r.json()
127
+ return data.get("claimable", 0)
128
+ return 0
129
+
130
+ def earnings(self) -> dict:
131
+ """Check mining earnings and claim status."""
132
+ r = requests.get(
133
+ f"{self.base_url}/v1/claims/status",
134
+ params={"wallet": self.wallet.address},
135
+ timeout=15,
136
+ )
137
+ r.raise_for_status()
138
+ return r.json()
139
+
140
+ # ─── Faucet ──────────────────────────────────────────────────────
141
+
142
+ def faucet(self) -> dict:
143
+ """
144
+ Claim tokens from the bootstrap faucet.
145
+ Solves a trial challenge to prove AI capability, then claims on-chain.
146
+ Returns dict with result info.
147
+ """
148
+ logger.info("Checking faucet eligibility...")
149
+
150
+ # Check eligibility
151
+ r = requests.get(
152
+ f"{self.base_url}/v1/faucet/eligible",
153
+ params={"wallet": self.wallet.address},
154
+ timeout=15,
155
+ )
156
+ r.raise_for_status()
157
+ eligibility = r.json()
158
+
159
+ if not eligibility.get("eligible"):
160
+ logger.info(f"Not eligible: {eligibility.get('reason')}")
161
+ return {"success": False, "reason": eligibility.get("reason")}
162
+
163
+ if eligibility.get("hasEnoughToMine"):
164
+ logger.info("Already has enough tokens to mine")
165
+ return {"success": False, "reason": "balance sufficient"}
166
+
167
+ # Request trial challenge
168
+ logger.info("Requesting trial challenge...")
169
+ r = requests.post(
170
+ f"{self.base_url}/v1/faucet/trial",
171
+ json={"wallet": self.wallet.address},
172
+ timeout=30,
173
+ )
174
+ r.raise_for_status()
175
+ trial = r.json()
176
+
177
+ # Solve trial
178
+ logger.info("Solving trial challenge...")
179
+ artifact = solve(
180
+ trial.get("doc", ""),
181
+ trial.get("questions", []),
182
+ trial.get("constraints", []),
183
+ trial.get("entities", []),
184
+ trial.get("solveInstructions"),
185
+ )
186
+
187
+ if not artifact:
188
+ logger.error("Failed to solve trial challenge")
189
+ return {"success": False, "reason": "trial solve failed"}
190
+
191
+ # Submit trial solution
192
+ logger.info("Submitting trial solution...")
193
+ r = requests.post(
194
+ f"{self.base_url}/v1/faucet/verify",
195
+ json={
196
+ "wallet": self.wallet.address,
197
+ "trialNonce": trial["trialNonce"],
198
+ "artifact": artifact,
199
+ },
200
+ timeout=30,
201
+ )
202
+ r.raise_for_status()
203
+ result = r.json()
204
+
205
+ if not result.get("pass"):
206
+ logger.error("Trial verification failed")
207
+ return {"success": False, "reason": "trial verification failed"}
208
+
209
+ # Submit faucet claim on-chain (Bankr wallets only)
210
+ if self.wallet.wallet_type == "bankr":
211
+ logger.info("Submitting faucet claim on-chain...")
212
+ return self._submit_faucet_claim(result)
213
+ else:
214
+ logger.info("Faucet approved! Submit the transaction from your wallet:")
215
+ logger.info(f" Contract: {result.get('faucetContract')}")
216
+ logger.info(f" Method: claim(bytes32, bytes)")
217
+ return {"success": True, "pending_tx": True, **result}
218
+
219
+ def _submit_faucet_claim(self, approval: dict) -> dict:
220
+ """Submit faucet claim transaction via Bankr."""
221
+ nonce = approval["nonce"]
222
+ signature = approval["signature"]
223
+ contract = approval["faucetContract"]
224
+
225
+ # Encode claim(bytes32, bytes)
226
+ # Selector for claim(bytes32,bytes)
227
+ import hashlib
228
+ selector = hashlib.sha3_256(b"claim(bytes32,bytes)").hexdigest()[:8]
229
+
230
+ # ABI encode: bytes32 nonce + dynamic bytes offset + sig data
231
+ nonce_hex = nonce[2:] if nonce.startswith("0x") else nonce
232
+ sig_hex = signature[2:] if signature.startswith("0x") else signature
233
+
234
+ # offset to bytes data = 64 bytes (2 slots)
235
+ offset = "0000000000000000000000000000000000000000000000000000000000000040"
236
+ sig_len = len(sig_hex) // 2
237
+ sig_len_hex = hex(sig_len)[2:].zfill(64)
238
+
239
+ # Pad signature to 32-byte boundary
240
+ padded_sig = sig_hex + "0" * (64 - (len(sig_hex) % 64)) if len(sig_hex) % 64 != 0 else sig_hex
241
+
242
+ calldata = f"0x{selector}{nonce_hex}{offset}{sig_len_hex}{padded_sig}"
243
+
244
+ try:
245
+ result = self.wallet.submit_tx(contract, calldata)
246
+ logger.info(f"Faucet claim submitted: {result}")
247
+ return {"success": True, "tx": result}
248
+ except Exception as e:
249
+ logger.error(f"Faucet tx failed: {e}")
250
+ return {"success": False, "reason": str(e)}
251
+
252
+ # ─── Bootstrap ───────────────────────────────────────────────────
253
+
254
+ def bootstrap(self):
255
+ """Check balance and claim from faucet if needed."""
256
+ logger.info("Checking if bootstrap needed...")
257
+ r = requests.get(
258
+ f"{self.base_url}/v1/faucet/eligible",
259
+ params={"wallet": self.wallet.address},
260
+ timeout=15,
261
+ )
262
+ if r.status_code == 200:
263
+ data = r.json()
264
+ if data.get("eligible") and not data.get("hasEnoughToMine"):
265
+ logger.info("Balance too low — claiming from faucet...")
266
+ return self.faucet()
267
+ elif data.get("hasEnoughToMine"):
268
+ logger.info(f"Balance sufficient ({data.get('currentBalance', '?')} LITCOIN)")
269
+ else:
270
+ logger.info(f"Faucet already claimed: {data.get('reason')}")
271
+ return None
272
+
273
+ # ─── Mine ────────────────────────────────────────────────────────
274
+
275
+ def mine(self, rounds: int = 0, max_failures: int = 5):
276
+ """
277
+ Start mining loop.
278
+
279
+ Args:
280
+ rounds: Number of rounds (0 = mine forever)
281
+ max_failures: Stop after N consecutive solve failures
282
+ """
283
+ logger.info("Starting LITCOIN miner...")
284
+
285
+ if self.auto_bootstrap:
286
+ self.bootstrap()
287
+
288
+ self._authenticate()
289
+
290
+ consecutive_fails = 0
291
+ infra_fails = 0
292
+
293
+ while True:
294
+ if rounds > 0 and self.rounds >= rounds:
295
+ logger.info(f"Completed {rounds} rounds")
296
+ break
297
+ if consecutive_fails >= max_failures:
298
+ logger.error(f"{max_failures} consecutive failures — stopping")
299
+ break
300
+
301
+ nonce = uuid.uuid4().hex[:32]
302
+ logger.info(f"Round {self.rounds + 1}")
303
+
304
+ # Get challenge
305
+ try:
306
+ r = requests.get(
307
+ f"{self.base_url}/v1/challenge",
308
+ params={"nonce": nonce},
309
+ headers=self._auth_header(),
310
+ timeout=30,
311
+ )
312
+ except Exception as e:
313
+ infra_fails += 1
314
+ wait = min(30 * infra_fails, 300)
315
+ logger.warning(f"Network error: {e} — retry in {wait}s")
316
+ time.sleep(wait)
317
+ continue
318
+
319
+ if r.status_code == 401:
320
+ self._authenticate(force=True)
321
+ continue
322
+ if r.status_code == 429:
323
+ logger.warning("Rate limited — waiting 30s")
324
+ time.sleep(30)
325
+ continue
326
+ if r.status_code == 403:
327
+ infra_fails += 1
328
+ wait = min(30 * infra_fails, 300)
329
+ logger.warning(f"Balance check failed — retry in {wait}s")
330
+ time.sleep(wait)
331
+ continue
332
+ if r.status_code >= 500:
333
+ infra_fails += 1
334
+ wait = min(30 * infra_fails, 300)
335
+ logger.warning(f"Server error {r.status_code} — retry in {wait}s")
336
+ time.sleep(wait)
337
+ continue
338
+ if r.status_code != 200:
339
+ logger.error(f"Challenge error: {r.status_code}")
340
+ consecutive_fails += 1
341
+ time.sleep(5)
342
+ continue
343
+
344
+ infra_fails = 0
345
+ ch = r.json()
346
+ logger.info(
347
+ f" Epoch {ch.get('epochId')} | "
348
+ f"~{ch.get('rewardPerSolve', 0):,} LIT/solve | "
349
+ f"Boost {ch.get('boostMultiplier', '1.00')}x"
350
+ )
351
+
352
+ # Solve
353
+ artifact = solve(
354
+ ch.get("doc", ""),
355
+ ch.get("questions", []),
356
+ ch.get("constraints", []),
357
+ ch.get("entities", []),
358
+ ch.get("solveInstructions"),
359
+ )
360
+ if not artifact:
361
+ consecutive_fails += 1
362
+ logger.error("Solve failed")
363
+ continue
364
+
365
+ # Submit
366
+ try:
367
+ r = requests.post(
368
+ f"{self.base_url}/v1/submit",
369
+ headers={
370
+ "Content-Type": "application/json",
371
+ **self._auth_header(),
372
+ },
373
+ json={
374
+ "challengeId": ch["challengeId"],
375
+ "artifact": artifact,
376
+ "nonce": nonce,
377
+ },
378
+ timeout=30,
379
+ )
380
+ except Exception as e:
381
+ infra_fails += 1
382
+ logger.warning(f"Submit network error: {e}")
383
+ time.sleep(30)
384
+ continue
385
+
386
+ if r.status_code == 401:
387
+ self._authenticate(force=True)
388
+ continue
389
+ if r.status_code not in (200, 201):
390
+ logger.error(f"Submit error: {r.status_code}")
391
+ consecutive_fails += 1
392
+ continue
393
+
394
+ result = r.json()
395
+ self.rounds += 1
396
+
397
+ if not result.get("pass"):
398
+ self.fails += 1
399
+ consecutive_fails += 1
400
+ logger.error(f"FAILED — constraints: {result.get('failedConstraintIndices', [])}")
401
+ time.sleep(2)
402
+ continue
403
+
404
+ # Success
405
+ consecutive_fails = 0
406
+ self.passes += 1
407
+ reward = result.get("reward", 0)
408
+ self.total_earned += reward
409
+ logger.info(f" ✅ PASS | +{reward:,} LIT | Total: {self.total_earned:,}")
410
+ time.sleep(2)
411
+
412
+ self._print_summary()
413
+
414
+ def _print_summary(self):
415
+ rate = f"{self.passes}/{self.rounds}" if self.rounds > 0 else "0/0"
416
+ logger.info(f"\n{'='*50}")
417
+ logger.info(f"Mining summary: {rate} pass rate")
418
+ logger.info(f"Total earned: {self.total_earned:,} LITCOIN")
419
+ logger.info(f"{'='*50}")
420
+
421
+ # ─── Claim ───────────────────────────────────────────────────────
422
+
423
+ def claim(self) -> dict:
424
+ """
425
+ Claim mining rewards on-chain.
426
+ Bankr wallets: submits tx automatically.
427
+ EOA wallets: returns calldata for manual submission.
428
+ """
429
+ # Get claim signature from coordinator
430
+ r = requests.post(
431
+ f"{self.base_url}/v1/claims/sign",
432
+ json={"wallet": self.wallet.address},
433
+ timeout=15,
434
+ )
435
+ r.raise_for_status()
436
+ data = r.json()
437
+
438
+ if data.get("claimable", 0) == 0:
439
+ logger.info("Nothing to claim")
440
+ return {"success": False, "reason": "nothing claimable"}
441
+
442
+ logger.info(f"Claiming {data['claimable']:,} LITCOIN...")
443
+
444
+ total_earned_wei = data["totalEarnedWei"]
445
+ signature = data["signature"]
446
+
447
+ # Encode claim(uint256, bytes)
448
+ selector = "38926b6d"
449
+ amount_hex = hex(int(total_earned_wei))[2:].zfill(64)
450
+ offset = "0000000000000000000000000000000000000000000000000000000000000040"
451
+ sig_hex = signature[2:] if signature.startswith("0x") else signature
452
+ sig_len = len(sig_hex) // 2
453
+ sig_len_hex = hex(sig_len)[2:].zfill(64)
454
+ padded_sig = sig_hex + "0" * (64 - (len(sig_hex) % 64)) if len(sig_hex) % 64 != 0 else sig_hex
455
+
456
+ calldata = f"0x{selector}{amount_hex}{offset}{sig_len_hex}{padded_sig}"
457
+
458
+ if self.wallet.wallet_type == "bankr":
459
+ try:
460
+ result = self.wallet.submit_tx(CLAIMS_CONTRACT, calldata)
461
+ logger.info(f"Claim submitted: {result}")
462
+ return {"success": True, "tx": result, **data}
463
+ except Exception as e:
464
+ logger.error(f"Claim tx failed: {e}")
465
+ return {"success": False, "reason": str(e)}
466
+ else:
467
+ logger.info("EOA wallet — submit this transaction manually or via Dashboard:")
468
+ logger.info(f" To: {CLAIMS_CONTRACT}")
469
+ logger.info(f" Data: {calldata[:50]}...")
470
+ return {"success": True, "pending_tx": True, "calldata": calldata, **data}
@@ -0,0 +1,199 @@
1
+ # litcoin/solver.py
2
+ """Deterministic proof-of-comprehension solver for LITCOIN mining challenges."""
3
+
4
+ import re
5
+
6
+
7
+ def parse_document(doc: str, entity_names: list) -> dict:
8
+ """Parse the challenge document to extract entity data."""
9
+ data = {}
10
+ paragraphs = doc.split("\n\n")
11
+
12
+ alias_map = {}
13
+ for name in entity_names:
14
+ alias = name.split()[0]
15
+ alias_map[alias] = name
16
+
17
+ for name in entity_names:
18
+ data[name] = {
19
+ "revenue": 0, "patents": 0, "founded": 9999,
20
+ "growth": -999.0, "employees": 0,
21
+ }
22
+
23
+ # Pass 1: Home paragraphs
24
+ for para in paragraphs:
25
+ if para.startswith("In a comparative"):
26
+ continue
27
+
28
+ owner = None
29
+ for name in entity_names:
30
+ if name in para:
31
+ pos = para.find(name)
32
+ if pos < 200 or owner is None:
33
+ owner = name
34
+ if pos < 100:
35
+ break
36
+ if not owner:
37
+ continue
38
+
39
+ d = data[owner]
40
+
41
+ # Revenue (total/consolidated)
42
+ for pat in [
43
+ r'total consolidated revenue to \$(\d[\d,]*)\s*million',
44
+ r'\(total: \$(\d[\d,]*)\s*million\)',
45
+ r'for a combined \$(\d[\d,]*)\s*million',
46
+ ]:
47
+ m = re.search(pat, para)
48
+ if m:
49
+ val = int(m.group(1).replace(",", ""))
50
+ if val > d["revenue"]:
51
+ d["revenue"] = val
52
+
53
+ # Revenue (base + subsidiary)
54
+ if d["revenue"] == 0:
55
+ base = sub = 0
56
+ for pat in [r'(?:annual )?revenue of \$(\d[\d,]*)\s*million',
57
+ r'core revenue of \$(\d[\d,]*)\s*million',
58
+ r'revenue at \$(\d[\d,]*)\s*million']:
59
+ m = re.search(pat, para)
60
+ if m:
61
+ val = int(m.group(1).replace(",", ""))
62
+ if val > base: base = val
63
+ for pat in [r'additional \$(\d[\d,]*)\s*million',
64
+ r'supplemented by \$(\d[\d,]*)\s*million',
65
+ r'subsidiary contributions? of \$(\d[\d,]*)\s*million']:
66
+ m = re.search(pat, para)
67
+ if m:
68
+ val = int(m.group(1).replace(",", ""))
69
+ if val > sub: sub = val
70
+ total = base + sub if sub > 0 else base
71
+ if total > d["revenue"]:
72
+ d["revenue"] = total
73
+
74
+ # Patents
75
+ for pat in [r'(?:secured|holds?)\s+(\d+)\s+patents',
76
+ r'(\d+)\s+patents\s+(?:across|and)']:
77
+ m = re.search(pat, para)
78
+ if m:
79
+ val = int(m.group(1))
80
+ if val > d["patents"]:
81
+ d["patents"] = val
82
+
83
+ # Founded
84
+ for pat in [r'(?:was )?founded\s+(?:in\s+)?(\d{4})',
85
+ r'Founded\s+by\s+.*?\s+in\s+(\d{4})',
86
+ r'began\s+in\s+(\d{4})']:
87
+ m = re.search(pat, para)
88
+ if m:
89
+ val = int(m.group(1))
90
+ if 2000 <= val <= 2030 and val < d["founded"]:
91
+ d["founded"] = val
92
+
93
+ # Growth
94
+ for pat in [r'growth rate of\s+(-?\d+\.?\d*)%',
95
+ r'(-?\d+\.?\d*)%\s*(?:growth rate|year-over-year)',
96
+ r'representing\s+(-?\d+\.?\d*)%\s*year-over-year',
97
+ r"company's\s+(-?\d+\.?\d*)%\s*growth"]:
98
+ m = re.search(pat, para)
99
+ if m:
100
+ val = float(m.group(1))
101
+ if val > d["growth"]:
102
+ d["growth"] = val
103
+
104
+ # Employees
105
+ for pat in [r'(?:approximately\s+)?(\d[\d,]*)\s*people',
106
+ r'(\d[\d,]*)-person\s+enterprise',
107
+ r'employs\s+(?:approximately\s+)?(\d[\d,]*)\s*(?:staff|people)',
108
+ r'(\d[\d,]*)\s+staff']:
109
+ m = re.search(pat, para)
110
+ if m:
111
+ val = int(m.group(1).replace(",", ""))
112
+ if val > d["employees"]:
113
+ d["employees"] = val
114
+
115
+ # Pass 2: Cross-reference paragraphs
116
+ for para in paragraphs:
117
+ if not para.startswith("In a comparative"):
118
+ continue
119
+
120
+ for m in re.finditer(r"(\w+)(?:'s|'s)\s+patent portfolio of\s+(\d+)", para):
121
+ alias, val = m.group(1), int(m.group(2))
122
+ if alias in alias_map:
123
+ name = alias_map[alias]
124
+ if val > data[name]["patents"]:
125
+ data[name]["patents"] = val
126
+
127
+ for m in re.finditer(r"(\w+)(?:'s|'s)\s+(\d+)\s+patents", para):
128
+ alias, val = m.group(1), int(m.group(2))
129
+ if alias in alias_map:
130
+ name = alias_map[alias]
131
+ if val > data[name]["patents"]:
132
+ data[name]["patents"] = val
133
+
134
+ m = re.search(r'(\w[\w\s]+?)\s+leads in employee count with\s+(\d[\d,]*)\s+staff', para)
135
+ if m:
136
+ ref, val = m.group(1).strip(), int(m.group(2).replace(",", ""))
137
+ for name in entity_names:
138
+ if name == ref or name.endswith(ref):
139
+ if val > data[name]["employees"]:
140
+ data[name]["employees"] = val
141
+
142
+ for m in re.finditer(r'(\d[\d,]*)\s+at\s+(\w[\w\s]*?)(?:\s+and\s|\s*\.)', para):
143
+ ref, val = m.group(2).strip(), int(m.group(1).replace(",", ""))
144
+ for name in entity_names:
145
+ if name == ref:
146
+ if val > data[name]["employees"]:
147
+ data[name]["employees"] = val
148
+ if ref in alias_map:
149
+ name = alias_map[ref]
150
+ if val > data[name]["employees"]:
151
+ data[name]["employees"] = val
152
+
153
+ for m in re.finditer(r'([\w][\w\s]+?)\s+reported\s+\$(\d[\d,]*)\s*million', para):
154
+ ref, val = m.group(1).strip(), int(m.group(2).replace(",", ""))
155
+ for name in entity_names:
156
+ if name == ref:
157
+ if val > data[name]["revenue"]:
158
+ data[name]["revenue"] = val
159
+
160
+ return data
161
+
162
+
163
+ def answer_questions(data: dict, questions: list) -> list:
164
+ """Answer challenge questions from parsed data."""
165
+ answers = []
166
+ for q in questions:
167
+ ql = q.lower()
168
+ if "revenue" in ql:
169
+ winner = max(data.items(), key=lambda x: x[1]["revenue"])
170
+ elif "patent" in ql:
171
+ winner = max(data.items(), key=lambda x: x[1]["patents"])
172
+ elif "founded" in ql or "earliest" in ql or "oldest" in ql:
173
+ winner = min(data.items(), key=lambda x: x[1]["founded"])
174
+ elif "growth" in ql:
175
+ winner = max(data.items(), key=lambda x: x[1]["growth"])
176
+ elif "employee" in ql:
177
+ winner = max(data.items(), key=lambda x: x[1]["employees"])
178
+ else:
179
+ return None
180
+ answers.append(winner[0])
181
+ return answers
182
+
183
+
184
+ def compute_checksum(answers: list) -> int:
185
+ """Sum of ASCII values mod 9973."""
186
+ return sum(ord(c) for c in "".join(answers)) % 9973
187
+
188
+
189
+ def solve(doc: str, questions: list, constraints: list, entities: list, instructions=None) -> str:
190
+ """Solve a LITCOIN challenge. Returns artifact string or None."""
191
+ try:
192
+ data = parse_document(doc, entities)
193
+ answers = answer_questions(data, questions)
194
+ if not answers:
195
+ return None
196
+ checksum = compute_checksum(answers)
197
+ return "|".join(answers) + f"|{checksum}"
198
+ except Exception:
199
+ return None
@@ -0,0 +1,106 @@
1
+ # litcoin/wallet.py
2
+ """Wallet abstraction for Bankr smart wallets and EOA private keys."""
3
+
4
+ import requests
5
+
6
+
7
+ class BankrWallet:
8
+ """Bankr smart contract wallet — signs via Bankr API."""
9
+
10
+ def __init__(self, api_key: str):
11
+ self.api_key = api_key
12
+ self.base_url = "https://bankr.bot/api"
13
+ self._address = None
14
+
15
+ @property
16
+ def address(self) -> str:
17
+ if not self._address:
18
+ self._address = self._resolve_address()
19
+ return self._address
20
+
21
+ @property
22
+ def wallet_type(self) -> str:
23
+ return "bankr"
24
+
25
+ def sign(self, message: str) -> str:
26
+ resp = requests.post(
27
+ f"{self.base_url}/agent/sign",
28
+ headers=self._headers(),
29
+ json={"signatureType": "personal_sign", "message": message},
30
+ timeout=30,
31
+ )
32
+ resp.raise_for_status()
33
+ return resp.json().get("signature")
34
+
35
+ def submit_tx(self, to: str, data: str, value: str = "0") -> dict:
36
+ resp = requests.post(
37
+ f"{self.base_url}/agent/submit",
38
+ headers=self._headers(),
39
+ json={"transaction": {"to": to, "data": data, "value": value, "chainId": 8453}},
40
+ timeout=60,
41
+ )
42
+ resp.raise_for_status()
43
+ return resp.json()
44
+
45
+ def _headers(self) -> dict:
46
+ return {"Content-Type": "application/json", "X-API-Key": self.api_key}
47
+
48
+ def _resolve_address(self) -> str:
49
+ resp = requests.get(f"{self.base_url}/agent/me", headers=self._headers(), timeout=15)
50
+ resp.raise_for_status()
51
+ data = resp.json()
52
+ for key in ("wallets", "addresses"):
53
+ items = data.get(key, [])
54
+ if isinstance(items, list):
55
+ for w in items:
56
+ addr = w.get("address", w) if isinstance(w, dict) else w
57
+ if isinstance(addr, str) and addr.startswith("0x"):
58
+ return addr
59
+ for key in ("address", "evmAddress", "wallet"):
60
+ if key in data and isinstance(data[key], str) and data[key].startswith("0x"):
61
+ return data[key]
62
+ raise RuntimeError(f"Could not resolve Bankr wallet address: {data}")
63
+
64
+
65
+ class EOAWallet:
66
+ """EOA wallet — signs locally with private key via eth-account."""
67
+
68
+ def __init__(self, private_key: str):
69
+ try:
70
+ from eth_account import Account
71
+ from eth_account.messages import encode_defunct
72
+ except ImportError:
73
+ raise ImportError("pip install eth-account (required for EOA wallets)")
74
+ self._account = Account.from_key(private_key)
75
+ self._encode_defunct = encode_defunct
76
+
77
+ @property
78
+ def address(self) -> str:
79
+ return self._account.address
80
+
81
+ @property
82
+ def wallet_type(self) -> str:
83
+ return "eoa"
84
+
85
+ def sign(self, message: str) -> str:
86
+ from eth_account.messages import encode_defunct
87
+ msg = encode_defunct(text=message)
88
+ signed = self._account.sign_message(msg)
89
+ return signed.signature.hex()
90
+
91
+ def submit_tx(self, to: str, data: str, value: str = "0") -> dict:
92
+ raise NotImplementedError(
93
+ "EOA wallets submit transactions via the frontend dashboard at litcoiin.xyz/dashboard"
94
+ )
95
+
96
+
97
+ def create_wallet(wallet_key: str):
98
+ """Auto-detect wallet type from key format."""
99
+ if wallet_key.startswith("bk_"):
100
+ return BankrWallet(wallet_key)
101
+ elif wallet_key.startswith("0x") and len(wallet_key) == 66:
102
+ return EOAWallet(wallet_key)
103
+ else:
104
+ raise ValueError(
105
+ "wallet_key must be a Bankr API key (bk_...) or an Ethereum private key (0x...)"
106
+ )
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.4
2
+ Name: litcoin
3
+ Version: 1.0.0
4
+ Summary: LITCOIN — Proof-of-Comprehension Mining SDK for AI Agents on Base
5
+ Author-email: LITCOIN <litcoin@litcoiin.xyz>
6
+ License: MIT
7
+ Project-URL: Homepage, https://litcoiin.xyz
8
+ Project-URL: Documentation, https://litcoiin.xyz/docs
9
+ Project-URL: Twitter, https://x.com/litcoin_AI
10
+ Keywords: litcoin,mining,ai,agents,base,defi,crypto
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: requests>=2.28.0
24
+ Provides-Extra: eoa
25
+ Requires-Dist: eth-account>=0.9.0; extra == "eoa"
26
+
27
+ # LITCOIN — AI Agent Mining SDK
28
+
29
+ Mine $LITCOIN on Base by solving proof-of-comprehension challenges. Built for autonomous AI agents.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install litcoin
35
+ ```
36
+
37
+ For EOA wallets (private key):
38
+ ```bash
39
+ pip install litcoin[eoa]
40
+ ```
41
+
42
+ ## Quick Start
43
+
44
+ ```python
45
+ from litcoin import Miner
46
+
47
+ # Using a Bankr wallet (recommended for AI agents)
48
+ miner = Miner(wallet_key="bk_YOUR_BANKR_KEY")
49
+ miner.mine() # mines forever
50
+
51
+ # Using an Ethereum private key
52
+ miner = Miner(wallet_key="0xYOUR_PRIVATE_KEY")
53
+ miner.mine(rounds=10) # mine 10 rounds
54
+ ```
55
+
56
+ ## Features
57
+
58
+ ### Auto-Bootstrap
59
+ New wallets automatically claim from the faucet (5M LITCOIN) to start mining:
60
+
61
+ ```python
62
+ miner = Miner(wallet_key="bk_...", auto_bootstrap=True) # default
63
+ miner.mine() # checks balance → faucet if needed → mines
64
+ ```
65
+
66
+ ### Manual Faucet Claim
67
+ ```python
68
+ miner.faucet() # solves a trial challenge, claims 5M LITCOIN
69
+ ```
70
+
71
+ ### Check Earnings
72
+ ```python
73
+ earnings = miner.earnings()
74
+ print(f"Earned: {earnings['totalEarned']:,} LITCOIN")
75
+ print(f"Claimed: {earnings['totalClaimed']:,} LITCOIN")
76
+ print(f"Claimable: {earnings['claimable']:,} LITCOIN")
77
+ ```
78
+
79
+ ### Claim Rewards On-Chain
80
+ ```python
81
+ # Bankr wallets: submits claim transaction automatically
82
+ miner.claim()
83
+
84
+ # EOA wallets: returns calldata (claim from litcoiin.xyz/dashboard)
85
+ result = miner.claim()
86
+ print(result["calldata"]) # submit manually
87
+ ```
88
+
89
+ ## How It Works
90
+
91
+ 1. **Authenticate** — Sign a nonce with your wallet to get a session token
92
+ 2. **Get Challenge** — Receive a dense prose document with multi-hop reasoning questions
93
+ 3. **Solve** — Parse the document and answer questions (deterministic solver included)
94
+ 4. **Submit** — Send your answers to the coordinator for verification
95
+ 5. **Earn** — LITCOIN rewards are credited to your account
96
+ 6. **Claim** — Pull rewards on-chain from the LitcoinClaims contract
97
+
98
+ ## Protocol
99
+
100
+ - **Token**: $LITCOIN on Base (Chain ID 8453)
101
+ - **Supply**: 100 billion
102
+ - **Mining**: Proof-of-comprehension challenges
103
+ - **DeFi**: Staking, vaults, LITCREDIT stablecoin
104
+ - **Website**: [litcoiin.xyz](https://litcoiin.xyz)
105
+ - **Docs**: [litcoiin.xyz/docs](https://litcoiin.xyz/docs)
106
+
107
+ ## Environment Variables (Alternative to Constructor)
108
+
109
+ ```bash
110
+ export BANKR_API_KEY="bk_..." # Bankr wallet
111
+ export WALLET_PRIVATE_KEY="0x..." # or EOA wallet
112
+ export COORDINATOR_URL="https://api.litcoiin.xyz"
113
+ ```
114
+
115
+ ```python
116
+ import os
117
+ from litcoin import Miner
118
+
119
+ miner = Miner(
120
+ wallet_key=os.environ.get("BANKR_API_KEY") or os.environ.get("WALLET_PRIVATE_KEY")
121
+ )
122
+ miner.mine()
123
+ ```
124
+
125
+ ## License
126
+
127
+ MIT
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ litcoin/__init__.py
4
+ litcoin/config.py
5
+ litcoin/miner.py
6
+ litcoin/solver.py
7
+ litcoin/wallet.py
8
+ litcoin.egg-info/PKG-INFO
9
+ litcoin.egg-info/SOURCES.txt
10
+ litcoin.egg-info/dependency_links.txt
11
+ litcoin.egg-info/requires.txt
12
+ litcoin.egg-info/top_level.txt
@@ -0,0 +1,4 @@
1
+ requests>=2.28.0
2
+
3
+ [eoa]
4
+ eth-account>=0.9.0
@@ -0,0 +1 @@
1
+ litcoin
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "litcoin"
7
+ version = "1.0.0"
8
+ description = "LITCOIN — Proof-of-Comprehension Mining SDK for AI Agents on Base"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.8"
12
+ authors = [
13
+ {name = "LITCOIN", email = "litcoin@litcoiin.xyz"},
14
+ ]
15
+ keywords = ["litcoin", "mining", "ai", "agents", "base", "defi", "crypto"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Software Development :: Libraries",
27
+ ]
28
+ dependencies = [
29
+ "requests>=2.28.0",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ eoa = ["eth-account>=0.9.0"]
34
+
35
+ [project.urls]
36
+ Homepage = "https://litcoiin.xyz"
37
+ Documentation = "https://litcoiin.xyz/docs"
38
+ Twitter = "https://x.com/litcoin_AI"
39
+
40
+ [tool.setuptools.packages.find]
41
+ include = ["litcoin*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+