Skip to content

Commit

Permalink
DeFiLlama-Curl v2.0.0 release
Browse files Browse the repository at this point in the history
Since the DeFiLlama API was updated with lots of endpoints, this Python wrapper is built from the ground up and updated to include all the modules and their functionalities for those endpoints.

The major changes are as follows:
* Updated the init file to include the package description and modules that can be imported.
* Updated the package version in version file.
* Added the utils helper function that includes the get requests and the argument parsing functions.
* Set utils file against improper import.
* Modified the package into different module files that can be imported and used as needed.
* Added docstrings for the module functions using restructured text style.
* Created docs for the package using Sphinx and uploaded on readthedocs.io.
* Updated .gitignore to exclude docs/build directory.
* Updated README.md to include the updated package details.
  • Loading branch information
the-praxs committed Mar 28, 2023
1 parent 8a4ade9 commit 6995160
Show file tree
Hide file tree
Showing 82 changed files with 22,835 additions and 289 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
build/
defillama/__pycache__/
DeFiLlama_Curl.egg-info/
dist/
dist/
build/
!docs/build/
88 changes: 10 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
# DeFiLlama Python API

[![Python 3.6](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/downloads/release/python-360/)
[![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/downloads/release/python-370/)
[![Python 3.8](https://img.shields.io/badge/python-3.8-blue.svg)](https://www.python.org/downloads/release/python-380/)
[![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/)
![Python](https://img.shields.io/pypi/pyversions/DeFiLlama-Curl?style=flat-square)
[![PyPi](https://img.shields.io/pypi/v/DeFiLlama-Curl?style=flat-square)](https://pypi.org/project/DeFiLlama-Curl/)
![Wheel](https://img.shields.io/pypi/wheel/DeFiLlama-Curl?style=flat-square)

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

-------

### Unofficial Python wrapper for the [DeFi Llama API](https://defillama.com/home) using PyCurl module
### Unofficial Python 3 wrapper for the [DeFiLlama API](https://defillama.com/home) using the fantastic [PyCurl](http://pycurl.io/) module

Inspired from itzmestar's [DeFi Llama](https://github.com/itzmestar/DeFiLlama) Python API.
Built from the ground up to be fast, reliable and easy to use.

For detailed information about the API endpoints, see [DeFi Llama API Documentation](https://docs.llama.fi/api)

Expand All @@ -22,84 +21,17 @@ Use pip to install:
```python
pip install DeFiLlama-Curl
```
<!--
*TODO: Add conda link* -->

-----------

### Authentication:

Endpoints are accessible without an API key.
Endpoints are accessible without requiring any API key.

-----------
<!-- -----------
### Documentation:
To import the package and initialize API client
```python
# Import library
from defillama import defillama

# Client object to interact with DeFi Llama API
llama = defillama()
```

#### TVL : Retrieve TVL data -->

1. **GET/protocols** : List all protocols on defillama along with their TVL.
```python
llama.get_protocols()
```

2. **GET/protocol/{protocol}** : Get historical TVL of a protocol and breakdown by token and chain.
```python
# For e.g. aave
llama.get_protocol(protocol='aave')
```

3. **GET/charts** : Get historical TVL of DeFi on all chains.
```python
llama.get_charts()
```

4. **GET/charts/{chain}** : Get historical TVL of a chain.
Chains can be obtained from **GET/chains** or the chains property on **GET/protocols**.
```python
# For e.g. Ethereum
llama.get_chart(chain='Ethereum')
```

5. **GET/tvl/{protocol}** : Get only protocol TVL as a number.
```python
# For e.g. uniswap
llama.get_tvl_protocol(protocol='uniswap')
```

6. **GET/chains** : Get current TVL of all chains.
```python
llama.get_chains()
```

#### coins : General blockchain data used by DeFi Llama and open-sourced -->

1. **GET/block/{chain}/{timestamp}** : Get the closest block on a timestamp (UNIX formatted).
Runs binary search over a blockchain's blocks to get the closest one to a timestamp.
Every time this is run DeFi Llama adds new data to their database, so each query permanently speeds up future queries.
```python
# For e.g. Fantom chain for timestamp 1650207158
llama.get_block_timestamp(block='fantom', timestamp=1650207158)
```

2. **POST/prices** : Get current or historical prices of tokens by contract address.
If timestamp is not provided we just return the latest data.
```python
# Sample data JSON
body = {
"coins": [
"ethereum:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"avax:0xd586e7f844cea2f87f50152665bcbc2c279d8d70"
],
"timestamp": 1603964988
}

# API usage
llama.post_prices(data=body)
```
*TODO: Add readthedocs link* -->
2 changes: 0 additions & 2 deletions bld.bat

This file was deleted.

1 change: 0 additions & 1 deletion build.sh

This file was deleted.

24 changes: 20 additions & 4 deletions defillama/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
from .__version__ import __title__, __description__, __url__
from .__version__ import __version__, __author_email__
from .__version__ import __author__, __license__, __copyright__
"""DeFiLlama-Curl is a Python wrapper for the DeFiLlama API built using the
fantastic PyCurl module.
from .defillama import defillama
The DeFiLlama API is a free, open-source API that provides access to DeFi
data. It is maintained by DeFiLlama.com, a DeFi data aggregator. This
Python wrapper is developed to prvoide access to those API requests in a
simple and easy to use manner.
This API contains the following submodules:
- abi-decoder: Function and event signatures decoded
- bridges: Data from DeFiLlama's bridges dashboard
- coins: General blockchain data used by DeFiLlama
- fees and revenue: Data from DeFiLlama's fees and revenue dashboard
- stablecoins: Data from DeFiLlama's stablecoins dashboard
- tvl: Retrieve TVL data
- volumes: Data from DeFiLlama's volumes dashboards
- yields: Data from DeFiLlama's yields/APY dashboard
"""

__all__ = ['__version__', '_utils', 'tvl', 'coins', 'stablecoins', 'yields',
'abi_decoder', 'bridges', 'volumes', 'fees_revenue']
5 changes: 2 additions & 3 deletions defillama/__version__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

__title__ = 'DeFiLlama-Curl'
__description__ = 'Unofficial Python wrapper for DeFi Llama API client using PyCurl module.'
__description__ = 'Unofficial Python wrapper for DeFi Llama API client using the PyCurl module.'
__url__ = 'https://github.com/the-praxs/DeFiLlama'
__version__ = '1.2'
__version__ = '2.0.0'
__author__ = 'Pratyush Shukla'
__author_email__ = '[email protected]'
__license__ = 'Apache License 2.0'
Expand Down
83 changes: 83 additions & 0 deletions defillama/_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import pycurl
import certifi
from json import loads, dumps
from io import BytesIO
from typing import List, Dict, Union

USERAGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'


def get(url: str) -> any:
"""Utility function for GET request to API
Function uses PyCurl to make a GET request to the API.
A user-agent is used to mimic a browser request.
Args:
url(str): String of the URL to make the request to.
url: str:
Returns:
any: Response from the API.
"""

buffer = BytesIO()
curl = pycurl.Curl()
curl.setopt(pycurl.USERAGENT, USERAGENT)
curl.setopt(pycurl.URL, url)
curl.setopt(pycurl.WRITEDATA, buffer)
curl.setopt(pycurl.CAINFO, certifi.where())
curl.perform()
curl.close()

response = buffer.getvalue()
response = loads(response.decode('utf-8'))

return response


def arg_parser(arg: Union[List[Dict[str, str]], Dict[str, List], List],
format: str) -> str:
"""Parse a list of dict of string key and value pairs to a formatted string
The string formats that can be requested are:
- normal: Characters are kept intact
- encoded: Characters are encoded to HTML URL encoding
- list: Characters are joined into a comma separated string
Args:
arg(Union[List[Dict[str):
arg(Union[List[Dict[str): Can be a list of dict of string key and value pairs, a dict of
arg(Union[List[Dict[str): Can be a list of dict of string key and value pairs, a dict of
string key and list of values, or a list of strings.
format(str): Requested format of the string.
arg: Union[List[Dict[str:
str]]:
Dict[str:
List]:
format: str:
Returns:
str: Parsed string output for the API request.
"""

if format == 'encoded':
arg = dumps(arg).replace(' ', '')

encodeDict = {'{': '%7B', '}': '%7D',
'[': '%5B', ']': '%5D',
'"': '%22'}

for char, code in encodeDict.items():
arg = arg.replace(char, code)

elif format == 'list':
arg = ','.join(arg)

elif format == 'normal':
arg = [f"{key}:{value}" for item in arg for key, value in item.items()]
arg = ','.join(arg)

return arg
70 changes: 70 additions & 0 deletions defillama/abi_decoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from typing import List, Dict
from ._utils import get, arg_parser

BASE_URL = "https://abi-decoder.llama.fi"


def get_signature_abi(func_sign: List,
events_sign: List = None) -> Dict[str, Dict[str, any]]:
"""**Returns the Application Binary Interface for a function
or event signature.**
*Endpoint: GET /fetch/signature*
Args:
func_sign(List): List of function signatures from the first 4 bytes
of the Keccak-256 hash
events_sign(List): List of event signatures
Returns:
Dict[str, Dict[str, any]]: Requested data
"""

func_sign = arg_parser(func_sign, format='list')

if events_sign is None:
url = f"{BASE_URL}/fetch/signature?functions={func_sign}"
else:
events_sign = arg_parser(events_sign, format='list')
url = f"{BASE_URL}/fetch/signature?functions={func_sign}&events={events_sign}"

return get(url)


def get_contract_signature_abi(chain: str,
address: str,
func_sign: List,
events_sign: List = None) -> Dict[str, Dict[str, any]]:
"""**Returns the verbose Application Binary Interface for a function or
event signature for a particular contract.**
*Endpoint: GET /fetch/contract/{chain}/{address}*
Args:
chain(str): Chain the smart contract is located on. Can be either
'arbitrum', 'avalanche', 'bsc', 'celo', 'ethereum', 'fantom',
'optimism', 'polygon', 'tron', 'xdai', 'heco'
address(str): Address of the smart contract
func_sign(List): List of function signatures from the first 4 bytes
of the Keccak-256 hash
events_sign(List): List of event signatures
Returns:
Dict[str, Dict[str, any]]: Requested data
"""

func_sign = arg_parser(func_sign, format='list')

if events_sign is None:
url = f"{BASE_URL}/fetch/contract/{chain}/{address}?functions={func_sign}"
else:
events_sign = arg_parser(events_sign, format='list')
url = f"{BASE_URL}/fetch/contract/{chain}/{address}?functions={func_sign}&events={events_sign}"

return get(url)
Loading

0 comments on commit 6995160

Please sign in to comment.