-
-
Save banteg/7c75fa2d4ebc371e5a3969cbcb6ddc24 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pathlib import Path | |
import cryo | |
import hvplot | |
import polars as pl | |
from ape import Contract, chain, networks | |
from eth_utils import encode_hex, keccak | |
from rich.console import Console | |
names = { | |
"DAI": "0x6B175474E89094C44Da98b954EedeAC495271d0F", | |
"USDT": "0xdAC17F958D2ee523a2206206994597C13D831ec7", | |
"USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", | |
"FRAX": "0x853d955aCEf822Db058eb8505911ED77F175b99e", | |
"USDe": "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3", | |
"FDUSD": "0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409", | |
} | |
console = Console() | |
print = console.log | |
def get_deploy_block(address): | |
resp = chain.provider._make_request("ots_getContractCreator", [address]) | |
return chain.provider.web3.eth.get_transaction(resp["hash"]).blockNumber | |
def decode_amount(data: pl.Series): | |
return data.map_elements(lambda x: float(int.from_bytes(x, "big")), pl.Float64) | |
def obtain_data(): | |
for name, address in names.items(): | |
print(name, address) | |
contract = Contract(address) | |
deploy = get_deploy_block(address) | |
match name: | |
case "USDT": | |
issue = keccak(text=contract.Issue.abi.selector) | |
redeem = keccak(text=contract.Redeem.abi.selector) | |
topics = { | |
"mint": [issue], | |
"burn": [redeem], | |
} | |
case _: | |
transfer = keccak(text=contract.Transfer.abi.selector) | |
topics = { | |
"mint": [transfer, bytes(32)], | |
"burn": [transfer, None, bytes(32)], | |
} | |
for topic_name, topic_data in topics.items(): | |
print(topic_name) | |
topic_data = topic_data + [None for _ in range(4 - len(topic_data))] | |
topic_data = { | |
f"topic{n}": [encode_hex(topic_data[n])] | |
for n in range(4) | |
if topic_data[n] | |
} | |
print(topic_data) | |
out_dir = Path(f"data/{name.lower()}/{topic_name}") | |
out_dir.mkdir(parents=True, exist_ok=True) | |
cryo.freeze( | |
["logs"], | |
blocks=[f"{deploy//10_000*10_000}:"], | |
align=True, | |
compression=["zstd", "3"], | |
contract=[address], | |
chunk_size=10_000, | |
output_dir=str(out_dir), | |
rpc=chain.provider.uri, | |
**topic_data, | |
) | |
def parse_data(): | |
dfs = [] | |
for name, address in names.items(): | |
print(f"parsing {name}") | |
contract = Contract(address) | |
scale = 10 ** contract.decimals() | |
inner_dfs = [] | |
for side in ["mint", "burn"]: | |
files = Path("data").glob(f"{name.lower()}/{side}/*.parquet") | |
sign = 1 if side == "mint" else -1 | |
inner_dfs.append( | |
pl.scan_parquet(files) | |
.with_columns( | |
delta=( | |
pl.col("data").map_batches(decode_amount) / float(scale) * sign | |
), | |
name=pl.lit(name), | |
) | |
.select(["block_number", "delta", "name"]) | |
) | |
df = ( | |
pl.concat(inner_dfs) | |
.sort("block_number") | |
.with_columns(supply=pl.cum_sum("delta")) | |
) | |
dfs.append(df) | |
blocks = pl.scan_parquet("data/blocks/*.parquet") | |
supplies = pl.concat(dfs) | |
base = ( | |
supplies.join(blocks, left_on="block_number", right_on="number", how="left") | |
.select(["block_number", "timestamp", "delta", "supply", "name"]) | |
.with_columns(pl.from_epoch("timestamp")) | |
.collect() | |
) | |
uptos = [] | |
for name in names: | |
wen = ( | |
base.filter((pl.col("name") == name) & (pl.col("supply") >= 2e9)) | |
.sort("block_number") | |
.item(0, "block_number") | |
) | |
upto = ( | |
base.filter((pl.col("name") == name) & (pl.col("block_number") <= wen)) | |
.sort("timestamp") | |
.group_by_dynamic("timestamp", every="1d") | |
.agg(pl.sum("delta"), pl.last("supply"), pl.last("name")) | |
.with_columns( | |
lifespan=( | |
pl.col("timestamp") - pl.col("timestamp").first() | |
).dt.total_days() | |
) | |
) | |
uptos.append(upto) | |
return pl.concat(uptos) | |
def main(): | |
obtain_data() | |
df = parse_data() | |
print(df) | |
plot_a = df.plot.step(x="timestamp", y="supply", by="name") | |
plot_b = df.plot.step(x="lifespan", y="supply", by="name") | |
hvplot.save(plot_a, "ethena_timestamp.html") | |
hvplot.save(plot_b, "ethena_lifespan.html") | |
if __name__ == "__main__": | |
with networks.parse_network_choice("ethereum:mainnet:geth"): | |
main() | |
console.rule() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment