cryptointerface 0.1.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.
- cryptointerface-0.1.0/.claude/.fuse_hidden000480fb000005da +12 -0
- cryptointerface-0.1.0/.claude/settings.local.json +15 -0
- cryptointerface-0.1.0/.gitignore +11 -0
- cryptointerface-0.1.0/.python-version +1 -0
- cryptointerface-0.1.0/PKG-INFO +354 -0
- cryptointerface-0.1.0/README.md +333 -0
- cryptointerface-0.1.0/cryptointerface/__init__.py +5 -0
- cryptointerface-0.1.0/cryptointerface/dex.py +892 -0
- cryptointerface-0.1.0/cryptointerface/flashloan.py +307 -0
- cryptointerface-0.1.0/cryptointerface/periphery/config.py +46 -0
- cryptointerface-0.1.0/cryptointerface/periphery/db.py +136 -0
- cryptointerface-0.1.0/cryptointerface/periphery/dex_architecture.json +119 -0
- cryptointerface-0.1.0/cryptointerface/periphery/dex_contracts.json +301 -0
- cryptointerface-0.1.0/cryptointerface/periphery/dex_contracts.py +56 -0
- cryptointerface-0.1.0/cryptointerface/periphery/enums.py +31 -0
- cryptointerface-0.1.0/cryptointerface/periphery/mapping.py +118 -0
- cryptointerface-0.1.0/cryptointerface/periphery/utils.py +6 -0
- cryptointerface-0.1.0/cryptointerface/providers/endpoints.json +25 -0
- cryptointerface-0.1.0/cryptointerface/providers/infura.py +36 -0
- cryptointerface-0.1.0/cryptointerface/routes.py +90 -0
- cryptointerface-0.1.0/cryptointerface/token.py +264 -0
- cryptointerface-0.1.0/cryptointerface/wallet.py +28 -0
- cryptointerface-0.1.0/helper.py +145 -0
- cryptointerface-0.1.0/main.py +50 -0
- cryptointerface-0.1.0/pools_v2.csv +2724 -0
- cryptointerface-0.1.0/pools_v3.csv +2724 -0
- cryptointerface-0.1.0/pyproject.toml +37 -0
- cryptointerface-0.1.0/requirements.txt +6 -0
- cryptointerface-0.1.0/test/conftest.py +27 -0
- cryptointerface-0.1.0/test/test_db.py +83 -0
- cryptointerface-0.1.0/test/test_dex.py +152 -0
- cryptointerface-0.1.0/test/test_token.py +145 -0
- cryptointerface-0.1.0/test/test_utils.py +32 -0
- cryptointerface-0.1.0/tokens.csv +2724 -0
- cryptointerface-0.1.0/uv.lock +1515 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(python:*)",
|
|
5
|
+
"Bash(pip install:*)",
|
|
6
|
+
"Bash(uv run:*)",
|
|
7
|
+
"WebFetch(domain:chainlist.org)",
|
|
8
|
+
"WebFetch(domain:docs.metamask.io)",
|
|
9
|
+
"WebFetch(domain:raw.githubusercontent.com)",
|
|
10
|
+
"Bash(.venv/bin/python -c \"import web3\")",
|
|
11
|
+
"Bash(.venv/bin/python -m pytest test/test_dex.py -m \"not network\")",
|
|
12
|
+
"Bash(uv add:*)"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cryptointerface
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Interface with cryptocurrency and DEX contracts. Store data locally for future use.
|
|
5
|
+
Project-URL: Source, https://github.com/William-Kruta/CryptoInterface
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: aave,arbitrage,crypto,defi,dex,uniswap,web3
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
13
|
+
Requires-Python: >=3.12
|
|
14
|
+
Requires-Dist: duckdb>=1.5
|
|
15
|
+
Requires-Dist: polars>=1.0
|
|
16
|
+
Requires-Dist: pyarrow>=14.0
|
|
17
|
+
Requires-Dist: python-dotenv>=1.0
|
|
18
|
+
Requires-Dist: requests>=2.33
|
|
19
|
+
Requires-Dist: web3>=7.0
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# CryptoInterface
|
|
23
|
+
|
|
24
|
+
A Python library for interacting with EVM-compatible DEXes — price fetching, swapping.
|
|
25
|
+
|
|
26
|
+
I have provided some starter data to enter in your database.
|
|
27
|
+
|
|
28
|
+
To do this, just write this code:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
from cryptointerface.periphery.db import insert_tokens_csv_to_db, insert_pools_csv_to_db
|
|
32
|
+
|
|
33
|
+
insert_tokens_csv_to_db()
|
|
34
|
+
insert_pools_csv_to_db()
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install cryptointerface
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or with [uv](https://github.com/astral-sh/uv):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv add cryptointerface
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Requirements:** Python 3.12+
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from cryptointerface import Dex, Token, Wallet, arbitrage_route
|
|
57
|
+
from cryptointerface.providers.infura import Infura
|
|
58
|
+
from cryptointerface.periphery.utils import to_wei, from_wei
|
|
59
|
+
from cryptointerface.periphery.enums import Network, Platform
|
|
60
|
+
|
|
61
|
+
infura = Infura(api_key="YOUR_INFURA_KEY")
|
|
62
|
+
|
|
63
|
+
# Look up a token
|
|
64
|
+
token = Token("WETH", chain_id=Network.ARBITRUM.value)
|
|
65
|
+
print(token.address, token.decimals)
|
|
66
|
+
|
|
67
|
+
# Fetch a price
|
|
68
|
+
dex = Dex("uniswap_v3", chain_id="42161", rpc_url=infura.get_url("42161"))
|
|
69
|
+
price = dex.get_price(weth_address, usdc_address)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Core Modules
|
|
75
|
+
|
|
76
|
+
### `Token` / `TokenInterface`
|
|
77
|
+
|
|
78
|
+
Resolves token metadata from a local DuckDB cache, downloading from CoinGecko on first use.
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from cryptointerface import Token, TokenInterface
|
|
82
|
+
|
|
83
|
+
token = Token("USDC", chain_id="42161")
|
|
84
|
+
print(token.address) # checksummed address
|
|
85
|
+
print(token.decimals) # 6
|
|
86
|
+
print(token.info) # polars DataFrame
|
|
87
|
+
|
|
88
|
+
# Build an ERC-20 approve transaction (unsigned)
|
|
89
|
+
tx = token.approve(
|
|
90
|
+
spender_address="0xRouter...",
|
|
91
|
+
amount=to_wei(1000, decimals=6),
|
|
92
|
+
owner_address="0xYourWallet",
|
|
93
|
+
rpc_url="https://...",
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`TokenInterface` provides the lower-level DB methods (`get_token_info`, `get_token_address`, `get_token_decimals`, `batch_save`, `update_decimals`).
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### `Dex` / `DexInterface`
|
|
102
|
+
|
|
103
|
+
Fetches pool addresses and prices, and builds swap transactions for all supported DEX protocols.
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from cryptointerface import Dex
|
|
107
|
+
|
|
108
|
+
dex = Dex("uniswap_v3", chain_id="42161", rpc_url="https://...")
|
|
109
|
+
|
|
110
|
+
# Pool address (cached in DuckDB on first call)
|
|
111
|
+
pool = dex.pool_address(token_a_address, token_b_address)
|
|
112
|
+
|
|
113
|
+
# Spot price — token_a denominated in token_b
|
|
114
|
+
price = dex.get_price(token_a_address, token_b_address)
|
|
115
|
+
|
|
116
|
+
# Build an unsigned swap transaction
|
|
117
|
+
tx = dex.interface.swap(
|
|
118
|
+
token_in=token_a_address,
|
|
119
|
+
token_out=token_b_address,
|
|
120
|
+
amount_in=to_wei(1.0),
|
|
121
|
+
dex_name="uniswap_v3",
|
|
122
|
+
chain_id="42161",
|
|
123
|
+
sender="0xYourWallet",
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Supported DEXes
|
|
128
|
+
|
|
129
|
+
| Name | Protocol | Chains |
|
|
130
|
+
| ---------------- | --------------- | ---------------------------------------------------- |
|
|
131
|
+
| `uniswap_v2` | Uniswap V2 | Ethereum, Sepolia |
|
|
132
|
+
| `uniswap_v3` | Uniswap V3 | Ethereum, Arbitrum, Polygon, Optimism, Base, Sepolia |
|
|
133
|
+
| `sushiswap_v2` | Uniswap V2 fork | Ethereum, Arbitrum, Polygon, Sepolia |
|
|
134
|
+
| `sushiswap_v3` | Uniswap V3 fork | Ethereum, Arbitrum, Polygon, Sepolia |
|
|
135
|
+
| `pancakeswap_v2` | Uniswap V2 fork | BSC, Ethereum |
|
|
136
|
+
| `pancakeswap_v3` | Uniswap V3 fork | BSC, Ethereum |
|
|
137
|
+
| `quickswap_v2` | Uniswap V2 fork | Polygon |
|
|
138
|
+
| `quickswap_v3` | Algebra V3 | Polygon |
|
|
139
|
+
| `camelot_v2` | Uniswap V2 fork | Arbitrum |
|
|
140
|
+
| `camelot_v3` | Algebra V3 | Arbitrum |
|
|
141
|
+
| `traderjoe_v1` | Uniswap V2 fork | Avalanche, Arbitrum |
|
|
142
|
+
| `aerodrome` | Solidly V2 | Base |
|
|
143
|
+
| `velodrome` | Solidly V2 | Optimism |
|
|
144
|
+
|
|
145
|
+
#### Protocols
|
|
146
|
+
|
|
147
|
+
- **Uniswap V2** — `getPair` factory, fixed fee per DEX, `getReserves` pricing
|
|
148
|
+
- **Uniswap V3** — `getPool` factory, per-pool fee tiers, `sqrtPriceX96` pricing
|
|
149
|
+
- **Algebra V3** — `poolByPair` factory, dynamic fees, no fee argument (QuickSwap, Camelot V3)
|
|
150
|
+
- **Solidly V2** — `getPool(stable: bool)` factory, stable/volatile pools (Aerodrome, Velodrome)
|
|
151
|
+
|
|
152
|
+
#### `create_dex_mapping`
|
|
153
|
+
|
|
154
|
+
Build a multi-DEX dict for use with `get_prices` / `arbitrage_route`:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from cryptointerface.dex import create_dex_mapping
|
|
158
|
+
|
|
159
|
+
dex_mapping = create_dex_mapping(
|
|
160
|
+
dex_names=["uniswap_v3", "sushiswap_v3", "camelot_v3"],
|
|
161
|
+
chain_ids=["42161"],
|
|
162
|
+
infura_obj=infura,
|
|
163
|
+
)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### `routes` — Prices & Arbitrage
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from cryptointerface import get_prices, arbitrage_route
|
|
172
|
+
|
|
173
|
+
# Parallel price fetch across all DEXes
|
|
174
|
+
prices = get_prices(dex_mapping, token_a_address, token_b_address)
|
|
175
|
+
# {"uniswap_v3": {"price": 1823.4, "pool": "0x...", "fee_bps": 5}, ...}
|
|
176
|
+
|
|
177
|
+
# Arbitrage analysis
|
|
178
|
+
route = arbitrage_route(dex_mapping, token_a_address, token_b_address)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`arbitrage_route` returns:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
{
|
|
185
|
+
"buy": {"dex": "camelot_v3", "price": 1820.1, "pool": "0x...", "fee_bps": 5},
|
|
186
|
+
"sell": {"dex": "uniswap_v3", "price": 1825.8, "pool": "0x...", "fee_bps": 5},
|
|
187
|
+
"spread_abs": 5.7,
|
|
188
|
+
"spread_pct": 0.3132,
|
|
189
|
+
"total_fee_pct": 0.1, # both legs combined
|
|
190
|
+
"net_spread_pct": 0.2132, # spread after fees
|
|
191
|
+
"profitable": True,
|
|
192
|
+
"all_prices": {...},
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Fees are sourced from `dex_architecture.json` — V3 fee tiers use the matched pool tier; V2 uses the fixed DEX fee.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### `Wallet`
|
|
201
|
+
|
|
202
|
+
Signs and broadcasts unsigned transactions built by `Dex`, `Token`, or `AaveFlashLoan`.
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
from cryptointerface import Wallet
|
|
206
|
+
|
|
207
|
+
wallet = Wallet(private_key="0x...", rpc_url="https://...")
|
|
208
|
+
|
|
209
|
+
tx_hash = wallet.sign_and_send(tx) # auto-fills nonce, gas, gasPrice
|
|
210
|
+
receipt = wallet.wait(tx_hash) # blocks until mined
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### `AaveFlashLoan`
|
|
216
|
+
|
|
217
|
+
Builds Aave V3 flash loan transactions. Supported chains: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Sepolia.
|
|
218
|
+
|
|
219
|
+
Flash loan fee: **0.09%** (9 bps).
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
from cryptointerface import AaveFlashLoan
|
|
223
|
+
from cryptointerface.periphery.utils import to_wei
|
|
224
|
+
|
|
225
|
+
fl = AaveFlashLoan(chain_id="42161", rpc_url="https://...")
|
|
226
|
+
|
|
227
|
+
# Single-asset flash loan (lower gas)
|
|
228
|
+
tx = fl.flash_loan_simple_tx(
|
|
229
|
+
receiver_contract="0xYourDeployedExecutor",
|
|
230
|
+
asset=usdc_address,
|
|
231
|
+
amount=to_wei(10_000, decimals=6),
|
|
232
|
+
sender=wallet.address,
|
|
233
|
+
)
|
|
234
|
+
tx_hash = wallet.sign_and_send(tx)
|
|
235
|
+
|
|
236
|
+
# Multi-asset flash loan
|
|
237
|
+
tx = fl.flash_loan_tx(
|
|
238
|
+
receiver_contract="0xYourDeployedExecutor",
|
|
239
|
+
assets=[weth_address, usdc_address],
|
|
240
|
+
amounts=[to_wei(5.0), to_wei(10_000, decimals=6)],
|
|
241
|
+
sender=wallet.address,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Check profitability after the flash loan fee
|
|
245
|
+
result = AaveFlashLoan.net_profit(
|
|
246
|
+
amount=to_wei(10_000, decimals=6),
|
|
247
|
+
gross_profit_wei=to_wei(15, decimals=6),
|
|
248
|
+
token_decimals=6,
|
|
249
|
+
)
|
|
250
|
+
# {"fee_wei": 9000, "net_profit_wei": 6000, "net_profit_human": 0.006, "is_profitable": True}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Solidity Executor Contract
|
|
254
|
+
|
|
255
|
+
The flash loan callback (`executeOperation`) must be implemented in Solidity. A full template is available as:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
print(AaveFlashLoan.EXECUTOR_TEMPLATE)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Deploy this contract once, paste your swap logic inside `executeOperation`, then pass its address as `receiver_contract`.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### `Infura`
|
|
266
|
+
|
|
267
|
+
RPC URL builder for Infura endpoints.
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
from cryptointerface.providers.infura import Infura
|
|
271
|
+
|
|
272
|
+
infura = Infura(api_key="YOUR_KEY")
|
|
273
|
+
rpc_url = infura.get_url("42161") # Arbitrum
|
|
274
|
+
|
|
275
|
+
# Add a custom endpoint
|
|
276
|
+
infura.add_endpoint(chain_id="10", endpoint="https://optimism-mainnet.infura.io/v3/")
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Local Database (DuckDB)
|
|
282
|
+
|
|
283
|
+
Token and pool data is cached locally in a DuckDB file (`~/.cryptointerface/data.db` by default). All reads/writes are thread-safe via thread-local connections and a write lock.
|
|
284
|
+
|
|
285
|
+
### Schema
|
|
286
|
+
|
|
287
|
+
**`tokens`** — `symbol`, `chain_id`, `address`, `decimals`
|
|
288
|
+
|
|
289
|
+
**`pools_v2`** — `dex`, `chain_id`, `token_0`, `token_1`, `address`
|
|
290
|
+
|
|
291
|
+
**`pools_v3`** — `dex`, `chain_id`, `token_0`, `token_1`, `fee`, `address`
|
|
292
|
+
|
|
293
|
+
### CSV Import / Export
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
from cryptointerface.periphery.db import (
|
|
297
|
+
export_tokens_to_csv,
|
|
298
|
+
export_pools_to_csv,
|
|
299
|
+
insert_tokens_csv_to_db,
|
|
300
|
+
insert_pools_csv_to_db,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
export_tokens_to_csv("tokens.csv")
|
|
304
|
+
export_pools_to_csv("pools_v2.csv", "pools_v3.csv")
|
|
305
|
+
|
|
306
|
+
insert_tokens_csv_to_db("tokens.csv")
|
|
307
|
+
insert_pools_csv_to_db("pools_v2.csv", "pools_v3.csv")
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Utilities
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
from cryptointerface.periphery.utils import to_wei, from_wei
|
|
316
|
+
|
|
317
|
+
to_wei(1.5, decimals=18) # 1500000000000000000
|
|
318
|
+
from_wei(1_000_000, decimals=6) # 1.0
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Enums
|
|
322
|
+
|
|
323
|
+
```python
|
|
324
|
+
from cryptointerface.periphery.enums import Network, Platform
|
|
325
|
+
|
|
326
|
+
Network.ARBITRUM.value # "42161"
|
|
327
|
+
Platform.UNISWAP_V3.value # "uniswap_v3"
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Networks:** `ETHEREUM`, `OPTIMISM`, `BSC`, `POLYGON`, `BASE`, `ARBITRUM`, `CELO`, `AVALANCHE`, `BLAST`, `ZORA`, `SEPOLIA`
|
|
331
|
+
|
|
332
|
+
**Platforms:** `UNISWAP_V2`, `UNISWAP_V3`, `SUSHISWAP_V2`, `SUSHISWAP_V3`, `PANCAKESWAP_V2`, `PANCAKESWAP_V3`, `QUICKSWAP_V2`, `QUICKSWAP_V3`, `CAMELOT_V2`, `CAMELOT_V3`, `TRADERJOE_V1`, `AERODROME`, `VELODROME`
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Running Tests
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
uv run pytest
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Network tests (require a live RPC) are skipped by default unless `SEPOLIA_RPC_URL` is set in your environment.
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Dependencies
|
|
347
|
+
|
|
348
|
+
| Package | Purpose |
|
|
349
|
+
| --------------- | ---------------------------- |
|
|
350
|
+
| `web3` | EVM RPC interaction |
|
|
351
|
+
| `duckdb` | Local persistent storage |
|
|
352
|
+
| `polars` | DataFrame operations |
|
|
353
|
+
| `requests` | CoinGecko API calls |
|
|
354
|
+
| `python-dotenv` | Environment variable loading |
|