Metadata-Version: 2.4
Name: cryptointerface
Version: 0.1.0
Summary: Interface with cryptocurrency and DEX contracts. Store data locally for future use.
Project-URL: Source, https://github.com/William-Kruta/CryptoInterface
License: MIT
Keywords: aave,arbitrage,crypto,defi,dex,uniswap,web3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.12
Requires-Dist: duckdb>=1.5
Requires-Dist: polars>=1.0
Requires-Dist: pyarrow>=14.0
Requires-Dist: python-dotenv>=1.0
Requires-Dist: requests>=2.33
Requires-Dist: web3>=7.0
Description-Content-Type: text/markdown

# CryptoInterface

A Python library for interacting with EVM-compatible DEXes — price fetching, swapping.

I have provided some starter data to enter in your database.

To do this, just write this code:

```
from cryptointerface.periphery.db import  insert_tokens_csv_to_db, insert_pools_csv_to_db

insert_tokens_csv_to_db()
insert_pools_csv_to_db()
```

## Installation

```bash
pip install cryptointerface
```

Or with [uv](https://github.com/astral-sh/uv):

```bash
uv add cryptointerface
```

**Requirements:** Python 3.12+

---

## Quick Start

```python
from cryptointerface import Dex, Token, Wallet, arbitrage_route
from cryptointerface.providers.infura import Infura
from cryptointerface.periphery.utils import to_wei, from_wei
from cryptointerface.periphery.enums import Network, Platform

infura = Infura(api_key="YOUR_INFURA_KEY")

# Look up a token
token = Token("WETH", chain_id=Network.ARBITRUM.value)
print(token.address, token.decimals)

# Fetch a price
dex = Dex("uniswap_v3", chain_id="42161", rpc_url=infura.get_url("42161"))
price = dex.get_price(weth_address, usdc_address)
```

---

## Core Modules

### `Token` / `TokenInterface`

Resolves token metadata from a local DuckDB cache, downloading from CoinGecko on first use.

```python
from cryptointerface import Token, TokenInterface

token = Token("USDC", chain_id="42161")
print(token.address)    # checksummed address
print(token.decimals)   # 6
print(token.info)       # polars DataFrame

# Build an ERC-20 approve transaction (unsigned)
tx = token.approve(
    spender_address="0xRouter...",
    amount=to_wei(1000, decimals=6),
    owner_address="0xYourWallet",
    rpc_url="https://...",
)
```

`TokenInterface` provides the lower-level DB methods (`get_token_info`, `get_token_address`, `get_token_decimals`, `batch_save`, `update_decimals`).

---

### `Dex` / `DexInterface`

Fetches pool addresses and prices, and builds swap transactions for all supported DEX protocols.

```python
from cryptointerface import Dex

dex = Dex("uniswap_v3", chain_id="42161", rpc_url="https://...")

# Pool address (cached in DuckDB on first call)
pool = dex.pool_address(token_a_address, token_b_address)

# Spot price — token_a denominated in token_b
price = dex.get_price(token_a_address, token_b_address)

# Build an unsigned swap transaction
tx = dex.interface.swap(
    token_in=token_a_address,
    token_out=token_b_address,
    amount_in=to_wei(1.0),
    dex_name="uniswap_v3",
    chain_id="42161",
    sender="0xYourWallet",
)
```

#### Supported DEXes

| Name             | Protocol        | Chains                                               |
| ---------------- | --------------- | ---------------------------------------------------- |
| `uniswap_v2`     | Uniswap V2      | Ethereum, Sepolia                                    |
| `uniswap_v3`     | Uniswap V3      | Ethereum, Arbitrum, Polygon, Optimism, Base, Sepolia |
| `sushiswap_v2`   | Uniswap V2 fork | Ethereum, Arbitrum, Polygon, Sepolia                 |
| `sushiswap_v3`   | Uniswap V3 fork | Ethereum, Arbitrum, Polygon, Sepolia                 |
| `pancakeswap_v2` | Uniswap V2 fork | BSC, Ethereum                                        |
| `pancakeswap_v3` | Uniswap V3 fork | BSC, Ethereum                                        |
| `quickswap_v2`   | Uniswap V2 fork | Polygon                                              |
| `quickswap_v3`   | Algebra V3      | Polygon                                              |
| `camelot_v2`     | Uniswap V2 fork | Arbitrum                                             |
| `camelot_v3`     | Algebra V3      | Arbitrum                                             |
| `traderjoe_v1`   | Uniswap V2 fork | Avalanche, Arbitrum                                  |
| `aerodrome`      | Solidly V2      | Base                                                 |
| `velodrome`      | Solidly V2      | Optimism                                             |

#### Protocols

- **Uniswap V2** — `getPair` factory, fixed fee per DEX, `getReserves` pricing
- **Uniswap V3** — `getPool` factory, per-pool fee tiers, `sqrtPriceX96` pricing
- **Algebra V3** — `poolByPair` factory, dynamic fees, no fee argument (QuickSwap, Camelot V3)
- **Solidly V2** — `getPool(stable: bool)` factory, stable/volatile pools (Aerodrome, Velodrome)

#### `create_dex_mapping`

Build a multi-DEX dict for use with `get_prices` / `arbitrage_route`:

```python
from cryptointerface.dex import create_dex_mapping

dex_mapping = create_dex_mapping(
    dex_names=["uniswap_v3", "sushiswap_v3", "camelot_v3"],
    chain_ids=["42161"],
    infura_obj=infura,
)
```

---

### `routes` — Prices & Arbitrage

```python
from cryptointerface import get_prices, arbitrage_route

# Parallel price fetch across all DEXes
prices = get_prices(dex_mapping, token_a_address, token_b_address)
# {"uniswap_v3": {"price": 1823.4, "pool": "0x...", "fee_bps": 5}, ...}

# Arbitrage analysis
route = arbitrage_route(dex_mapping, token_a_address, token_b_address)
```

`arbitrage_route` returns:

```python
{
    "buy":            {"dex": "camelot_v3", "price": 1820.1, "pool": "0x...", "fee_bps": 5},
    "sell":           {"dex": "uniswap_v3", "price": 1825.8, "pool": "0x...", "fee_bps": 5},
    "spread_abs":     5.7,
    "spread_pct":     0.3132,
    "total_fee_pct":  0.1,       # both legs combined
    "net_spread_pct": 0.2132,    # spread after fees
    "profitable":     True,
    "all_prices":     {...},
}
```

Fees are sourced from `dex_architecture.json` — V3 fee tiers use the matched pool tier; V2 uses the fixed DEX fee.

---

### `Wallet`

Signs and broadcasts unsigned transactions built by `Dex`, `Token`, or `AaveFlashLoan`.

```python
from cryptointerface import Wallet

wallet = Wallet(private_key="0x...", rpc_url="https://...")

tx_hash = wallet.sign_and_send(tx)   # auto-fills nonce, gas, gasPrice
receipt = wallet.wait(tx_hash)       # blocks until mined
```

---

### `AaveFlashLoan`

Builds Aave V3 flash loan transactions. Supported chains: Ethereum, Optimism, BSC, Polygon, Base, Arbitrum, Avalanche, Sepolia.

Flash loan fee: **0.09%** (9 bps).

```python
from cryptointerface import AaveFlashLoan
from cryptointerface.periphery.utils import to_wei

fl = AaveFlashLoan(chain_id="42161", rpc_url="https://...")

# Single-asset flash loan (lower gas)
tx = fl.flash_loan_simple_tx(
    receiver_contract="0xYourDeployedExecutor",
    asset=usdc_address,
    amount=to_wei(10_000, decimals=6),
    sender=wallet.address,
)
tx_hash = wallet.sign_and_send(tx)

# Multi-asset flash loan
tx = fl.flash_loan_tx(
    receiver_contract="0xYourDeployedExecutor",
    assets=[weth_address, usdc_address],
    amounts=[to_wei(5.0), to_wei(10_000, decimals=6)],
    sender=wallet.address,
)

# Check profitability after the flash loan fee
result = AaveFlashLoan.net_profit(
    amount=to_wei(10_000, decimals=6),
    gross_profit_wei=to_wei(15, decimals=6),
    token_decimals=6,
)
# {"fee_wei": 9000, "net_profit_wei": 6000, "net_profit_human": 0.006, "is_profitable": True}
```

#### Solidity Executor Contract

The flash loan callback (`executeOperation`) must be implemented in Solidity. A full template is available as:

```python
print(AaveFlashLoan.EXECUTOR_TEMPLATE)
```

Deploy this contract once, paste your swap logic inside `executeOperation`, then pass its address as `receiver_contract`.

---

### `Infura`

RPC URL builder for Infura endpoints.

```python
from cryptointerface.providers.infura import Infura

infura = Infura(api_key="YOUR_KEY")
rpc_url = infura.get_url("42161")   # Arbitrum

# Add a custom endpoint
infura.add_endpoint(chain_id="10", endpoint="https://optimism-mainnet.infura.io/v3/")
```

---

## Local Database (DuckDB)

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.

### Schema

**`tokens`** — `symbol`, `chain_id`, `address`, `decimals`

**`pools_v2`** — `dex`, `chain_id`, `token_0`, `token_1`, `address`

**`pools_v3`** — `dex`, `chain_id`, `token_0`, `token_1`, `fee`, `address`

### CSV Import / Export

```python
from cryptointerface.periphery.db import (
    export_tokens_to_csv,
    export_pools_to_csv,
    insert_tokens_csv_to_db,
    insert_pools_csv_to_db,
)

export_tokens_to_csv("tokens.csv")
export_pools_to_csv("pools_v2.csv", "pools_v3.csv")

insert_tokens_csv_to_db("tokens.csv")
insert_pools_csv_to_db("pools_v2.csv", "pools_v3.csv")
```

---

## Utilities

```python
from cryptointerface.periphery.utils import to_wei, from_wei

to_wei(1.5, decimals=18)     # 1500000000000000000
from_wei(1_000_000, decimals=6)  # 1.0
```

### Enums

```python
from cryptointerface.periphery.enums import Network, Platform

Network.ARBITRUM.value   # "42161"
Platform.UNISWAP_V3.value  # "uniswap_v3"
```

**Networks:** `ETHEREUM`, `OPTIMISM`, `BSC`, `POLYGON`, `BASE`, `ARBITRUM`, `CELO`, `AVALANCHE`, `BLAST`, `ZORA`, `SEPOLIA`

**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`

---

## Running Tests

```bash
uv run pytest
```

Network tests (require a live RPC) are skipped by default unless `SEPOLIA_RPC_URL` is set in your environment.

---

## Dependencies

| Package         | Purpose                      |
| --------------- | ---------------------------- |
| `web3`          | EVM RPC interaction          |
| `duckdb`        | Local persistent storage     |
| `polars`        | DataFrame operations         |
| `requests`      | CoinGecko API calls          |
| `python-dotenv` | Environment variable loading |
